OSDN Git Service

Update Settings to use new fingerprint API
authorJim Miller <jaggies@google.com>
Tue, 24 Mar 2015 23:02:59 +0000 (16:02 -0700)
committerJim Miller <jaggies@google.com>
Tue, 24 Mar 2015 23:02:59 +0000 (16:02 -0700)
Bug 16487912

Change-Id: I99ac78f476d43f6b87f5dd20e597c51ed08d2c0e

res/values/strings.xml
src/com/android/settings/ChooseLockGeneric.java
src/com/android/settings/FingerprintEnroll.java
src/com/android/settings/FingerprintSettings.java
src/com/android/settings/SecuritySettings.java

index f4edc7a..0b6a3b4 100644 (file)
     </plurals>
     <!-- Introduction title shown in fingerprint enrollment dialog [CHAR LIMIT=22] -->
     <string name="security_settings_fingerprint_enroll_onboard_title">Fingerprint setup</string>
-    <!-- Introduction detail message shown in fingerprint enrollment dialog -->
+    <!-- Introduction message shown in fingerprint enrollment dialog when the user needs to choose an 
+         alternate screen unlock (pin, pattern or password) as a backup to fingerprint. -->
     <string name="security_settings_fingerprint_enroll_onboard_message">
         To use your fingerprint to unlock your screen or confirm purchases, we\'ll need to:
         \n\n\u2713 Set up your background screen lock method
     <string name="fingerprint_enroll_button_add">Add</string>
     <!-- Button text shown at the end of enrollment that allows the user to move to the next step -->
     <string name="fingerprint_enroll_button_next">Next</string>
-    <!-- Error message shown when the fingerprint cannot be recognized -->
-    <string name="fingerprint_acquired_try_again">Partial fingerprint detected. Please try again.</string>
-    <!-- Error message shown when the fingerprint sensor needs cleaning -->
-    <string name="fingerprint_acquired_imager_dirty">Fingerprint sensor is dirty. Please clean and try again.</string>
-    <!-- Error message shown when the user removes their finger from the sensor too quickly -->
-    <string name="fingerprint_acquired_too_fast">Finger moved to fast. Please try again.</string>
-    <!-- Error message shown when the user moves their finger too slowly -->
-    <string name="fingerprint_acquired_too_slow">Finger moved to slow. Please try again.</string>
-    <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
-    <string name="fingerprint_error_unable_to_process">Unable to process. Try again.</string>
-    <!-- Error message shown when the fingerprint hardware can't be accessed -->
-    <string name="fingerprint_error_hw_not_available">Hardware not available.</string>
-    <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
-    <string name="fingerprint_error_no_space">Fingerprint can\'t be stored. Please remove an existing fingerprint.</string>
-    <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
-    <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
 
     <!-- Title of the preferences category for preference items to control encryption -->
     <string name="crypt_keeper_settings_title">Encryption</string>
index 6cec420..b6f907e 100644 (file)
@@ -34,11 +34,14 @@ import android.os.UserManager;
 import android.preference.Preference;
 import android.preference.PreferenceScreen;
 import android.security.KeyStore;
+import android.service.fingerprint.Fingerprint;
 import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintManager.RemovalCallback;
 import android.util.EventLog;
 import android.util.Log;
 import android.view.accessibility.AccessibilityManager;
+import android.widget.Toast;
+
 import com.android.internal.widget.LockPatternUtils;
 
 import java.util.List;
@@ -96,6 +99,18 @@ public class ChooseLockGeneric extends SettingsActivity {
         private boolean mRequirePassword;
         private LockPatternUtils mLockPatternUtils;
         private FingerprintManager mFingerprintManager;
+        private RemovalCallback mRemovalCallback = new RemovalCallback() {
+
+            @Override
+            public void onRemovalSucceeded(Fingerprint fingerprint) {
+                Log.v(TAG, "Fingerprint removed: " + fingerprint.getFingerId());
+            }
+
+            @Override
+            public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
+                Toast.makeText(getActivity(), errString, Toast.LENGTH_SHORT);
+            }
+        };
 
         @Override
         public void onCreate(Bundle savedInstanceState) {
@@ -400,25 +415,15 @@ public class ChooseLockGeneric extends SettingsActivity {
             }
         }
 
-        // TODO: This is only required because we used to enforce clients have a listener,
-        // which is no longer required in the new API.  Remove when that happens.
-        FingerprintManagerReceiver mReceiver = new FingerprintManagerReceiver() {
-            public void onRemoved(int fingerprintId) {
-                Log.v(TAG, "onRemoved(id=" + fingerprintId + ")");
-            }
-        };
-
         private void removeAllFingerprintTemplates() {
             if (mFingerprintManager != null && mFingerprintManager.isHardwareDetected()) {
-                mFingerprintManager.startListening(mReceiver);
-                mFingerprintManager.remove(0 /* all fingerprint templates */);
+                mFingerprintManager.remove(new Fingerprint(null, 0, 0, 0), mRemovalCallback);
             }
         }
 
         @Override
         public void onDestroy() {
             super.onDestroy();
-            mFingerprintManager.stopListening();
         }
 
         @Override
index 376444e..931fb9c 100644 (file)
@@ -24,16 +24,16 @@ import android.app.Fragment;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Resources;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.media.AudioAttributes;
 import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.Vibrator;
 import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -82,12 +82,13 @@ public class FingerprintEnroll extends SettingsActivity {
     }
 
     public static class FingerprintEnrollFragment extends Fragment implements View.OnClickListener {
+        private static final String EXTRA_PROGRESS = "progress";
+        private static final String EXTRA_STAGE = "stage";
         private static final int PROGRESS_BAR_MAX = 10000;
         private static final String TAG = "FingerprintEnroll";
         private static final boolean DEBUG = true;
         private static final int CONFIRM_REQUEST = 101;
         private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
-        private static final long ENROLL_TIMEOUT = 300*1000;
         private static final int FINISH_DELAY = 250;
 
         private PowerManager mPowerManager;
@@ -128,6 +129,7 @@ public class FingerprintEnroll extends SettingsActivity {
             @Override
             public void onAnimationCancel(Animator animation) { }
         };
+        private CancellationSignal mEnrollmentCancel = new CancellationSignal();
 
         // This contains a list of all views managed by the UI. Used to determine which views
         // need to be shown/hidden at each stage. It should be the union of the lists that follow
@@ -240,13 +242,12 @@ public class FingerprintEnroll extends SettingsActivity {
                 case EnrollingFindSensor:
                     mEnrollmentSteps = -1;
                     mEnrolling = false;
-                    mFingerprintManager.stopListening();
                     break;
 
                 case EnrollingStart:
                     mEnrollmentSteps = -1;
-                    mFingerprintManager.startListening(mReceiver);
-                    mFingerprintManager.enroll(ENROLL_TIMEOUT);
+                    long challenge = 0x12345; // TODO: get from keyguard confirmation
+                    mFingerprintManager.enroll(challenge, mEnrollmentCallback, mEnrollmentCancel,0);
                     mProgressBar.setProgress(0);
                     mEnrolling = true;
                     startFingerprintAnimator(); // XXX hack - this should follow fingerprint detection
@@ -257,12 +258,10 @@ public class FingerprintEnroll extends SettingsActivity {
 
                 case EnrollingFinish:
                     stopFingerprintAnimator(); // XXX hack - this should follow fingerprint detection
-                    mFingerprintManager.stopListening();
                     mEnrolling = false;
                     break;
 
                 default:
-                    mFingerprintManager.stopListening();
                     break;
             }
         }
@@ -270,7 +269,7 @@ public class FingerprintEnroll extends SettingsActivity {
         private void cancelEnrollment() {
             if (mEnrolling) {
                 if (DEBUG) Log.v(TAG, "Cancel enrollment\n");
-                mFingerprintManager.enrollCancel();
+                mEnrollmentCancel.cancel();
                 mEnrolling = false;
             }
         }
@@ -278,9 +277,7 @@ public class FingerprintEnroll extends SettingsActivity {
         @Override
         public void onDetach() {
             super.onDetach();
-            // Do a little cleanup
-            cancelEnrollment();
-            mFingerprintManager.stopListening();
+            cancelEnrollment(); // Do a little cleanup
         }
 
         private void updateProgress(int progress) {
@@ -300,6 +297,10 @@ public class FingerprintEnroll extends SettingsActivity {
             mProgressAnim = anim;
         }
 
+        protected void setMessage(CharSequence msg) {
+            if (msg != null) mMessageText.setText(msg);
+        }
+
         private void setMessage(int id) {
             if (id != 0) mMessageText.setText(id);
         }
@@ -308,9 +309,11 @@ public class FingerprintEnroll extends SettingsActivity {
             if (title != 0) mTitleText.setText(title);
         }
 
-        private FingerprintManagerReceiver mReceiver = new FingerprintManagerReceiver() {
-            public void onEnrollResult(int fingerprintId, int remaining) {
-                if (DEBUG) Log.v(TAG, "onEnrollResult(id=" + fingerprintId + ", rem=" + remaining);
+        private EnrollmentCallback mEnrollmentCallback = new EnrollmentCallback() {
+
+            @Override
+            public void onEnrollmentProgress(int remaining) {
+                if (DEBUG) Log.v(TAG, "onEnrollResult(id=" + ", rem=" + remaining);
                 if (mEnrollmentSteps == -1) {
                     mEnrollmentSteps = remaining;
                     updateStage(Stage.EnrollingRepeat);
@@ -325,62 +328,14 @@ public class FingerprintEnroll extends SettingsActivity {
                 }
             }
 
-            public void onError(int error) {
-                switch(error) {
-                    case FingerprintManager.FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
-                        setMessage(R.string.fingerprint_error_unable_to_process);
-                        break;
-                    case FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE:
-                        setMessage(R.string.fingerprint_error_hw_not_available);
-                        break;
-                    case FingerprintManager.FINGERPRINT_ERROR_NO_SPACE:
-                        setMessage(R.string.fingerprint_error_no_space);
-                        break;
-                    case FingerprintManager.FINGERPRINT_ERROR_TIMEOUT:
-                        setMessage(R.string.fingerprint_error_timeout);
-                        break;
-                    case FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER:
-                        Log.w(TAG, "Receiver not registered");
-                        break;
-                }
-            }
-
-            public void onRemoved(int fingerprintId) {
-                if (DEBUG) Log.v(TAG, "onRemoved(id=" + fingerprintId + ")");
-            }
-
             @Override
-            public void onProcessed(int fingerprintId) {
-                if (DEBUG) Log.v(TAG, "onProcessed(id=" + fingerprintId + ")");
+            public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
+                setMessage(helpString);
             }
 
-            public void onAcquired(int scanInfo) {
-                int msgId = 0;
-                startFingerprintAnimator();
-                switch(scanInfo) {
-                    case FingerprintManager.FINGERPRINT_ACQUIRED_GOOD:
-                        break;
-                    case FingerprintManager.FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
-                        msgId = R.string.fingerprint_acquired_imager_dirty;
-                        break;
-                    case FingerprintManager.FINGERPRINT_ACQUIRED_TOO_SLOW:
-                        msgId = R.string.fingerprint_acquired_too_fast;
-                        break;
-                    case FingerprintManager.FINGERPRINT_ACQUIRED_TOO_FAST:
-                        msgId = R.string.fingerprint_acquired_too_slow;
-                        break;
-                    case FingerprintManager.FINGERPRINT_ACQUIRED_PARTIAL:
-                    case FingerprintManager.FINGERPRINT_ACQUIRED_INSUFFICIENT:
-                        msgId = R.string.fingerprint_acquired_try_again;
-                        break;
-                    default:
-                        // Try not to be too verbose in the UI. The user just needs to try again.
-                        // Log the message so we can dig into the issue if necessary.
-                        Log.w(TAG, "Try again because scanInfo was " + scanInfo);
-                        msgId = R.string.fingerprint_acquired_try_again;
-                        break;
-                }
-                setMessage(msgId);
+            @Override
+            public void onEnrollmentError(int errMsgId, CharSequence errString) {
+                setMessage(errString);
             }
         };
 
@@ -432,6 +387,31 @@ public class FingerprintEnroll extends SettingsActivity {
         }
 
         @Override
+        public void onSaveInstanceState(final Bundle outState) {
+            super.onSaveInstanceState(outState);
+            outState.putString(EXTRA_STAGE, mStage.toString());
+            if (mStage == Stage.EnrollingRepeat) {
+                outState.putInt(EXTRA_PROGRESS, mProgressBar.getProgress());
+            }
+        }
+
+        @Override
+        public void onActivityCreated(Bundle savedInstanceState) {
+            super.onActivityCreated(savedInstanceState);
+            if (savedInstanceState != null) {
+                //probably orientation change
+                String stageSaved = savedInstanceState.getString(EXTRA_STAGE, null);
+                if (stageSaved != null) {
+                    Stage stage = Stage.valueOf(stageSaved);
+                    updateStage(stage);
+                    if (stage == Stage.EnrollingRepeat) {
+                        mProgressBar.setProgress(savedInstanceState.getInt(EXTRA_PROGRESS));
+                    }
+                }
+            }
+        }
+
+        @Override
         public void onClick(View v) {
             switch(v.getId()) {
                 case R.id.fingerprint_enroll_button_add:
index e7443e3..db87065 100644 (file)
@@ -29,13 +29,16 @@ import android.preference.Preference;
 import android.preference.Preference.OnPreferenceChangeListener;
 import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
+import android.service.fingerprint.Fingerprint;
 import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
-import android.service.fingerprint.FingerprintManager.FingerprintItem;
+import android.service.fingerprint.FingerprintManager.AuthenticationCallback;
+import android.service.fingerprint.FingerprintManager.RemovalCallback;
+import android.service.fingerprint.FingerprintManager.AuthenticationResult;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
 import android.widget.EditText;
+import android.widget.Toast;
 
 import com.android.settings.search.Indexable;
 
@@ -68,6 +71,7 @@ public class FingerprintSettings extends SettingsActivity {
 
     public static class FingerprintSettingsFragment extends SettingsPreferenceFragment
         implements OnPreferenceChangeListener, Indexable {
+        private static final int MAX_RETRY_ATTEMPTS = 5;
         private static final String TAG = "FingerprintSettings";
         private static final String KEY_FINGERPRINT_ITEM = "key_fingerprint_item";
         private static final String KEY_USAGE_CATEGORY = "fingerprint_usage_category";
@@ -82,10 +86,54 @@ public class FingerprintSettings extends SettingsActivity {
         private static final int ADD_FINGERPRINT_REQUEST = 10;
 
         private static final boolean ENABLE_USAGE_CATEGORY = false;
+        protected static final boolean DEBUG = true;
 
         private FingerprintManager mFingerprintManager;
         private EditText mDialogTextField;
         private PreferenceGroup mManageCategory;
+        private AuthenticationCallback mAuthCallback = new AuthenticationCallback() {
+            int mAttempts;
+            @Override
+            public void onAuthenticationSucceeded(AuthenticationResult result) {
+                mHandler.obtainMessage(MSG_HIGHLIGHT_FINGERPRINT_ITEM,
+                        result.getFingerprint().getFingerId(), 0).sendToTarget();
+                retryFingerprint(true);
+            }
+
+            @Override
+            public void onAuthenticationError(int errMsgId, CharSequence errString) {
+                Toast.makeText(getActivity(), errString, Toast.LENGTH_SHORT);
+                retryFingerprint(false);
+            }
+
+            private void retryFingerprint(boolean resetAttempts) {
+                if (resetAttempts) {
+                    mAttempts = 0;
+                }
+                if (mAttempts < MAX_RETRY_ATTEMPTS) {
+                    mFingerprintManager.authenticate(null, mAuthCallback, null, 0);
+                }
+                mAttempts++;
+            }
+
+            @Override
+            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+                Toast.makeText(getActivity(), helpString, Toast.LENGTH_SHORT);
+            }
+        };
+        private RemovalCallback mRemoveCallback = new RemovalCallback() {
+
+            @Override
+            public void onRemovalSucceeded(Fingerprint fingerprint) {
+                mHandler.obtainMessage(MSG_REFRESH_FINGERPRINT_TEMPLATES,
+                        fingerprint.getFingerId(), 0).sendToTarget();
+            }
+
+            @Override
+            public void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString) {
+                Toast.makeText(getActivity(), errString, Toast.LENGTH_SHORT);
+            }
+        };
         private final Handler mHandler = new Handler() {
             public void handleMessage(android.os.Message msg) {
                 switch (msg.what) {
@@ -104,20 +152,7 @@ public class FingerprintSettings extends SettingsActivity {
             super.onCreate(savedInstanceState);
             mFingerprintManager = (FingerprintManager) getActivity().getSystemService(
                     Context.FINGERPRINT_SERVICE);
-            mFingerprintManager.startListening(new FingerprintManagerReceiver() {
-                @Override
-                public void onRemoved(int fingerprintId) {
-                    mHandler.obtainMessage(MSG_REFRESH_FINGERPRINT_TEMPLATES, fingerprintId, 0)
-                            .sendToTarget();
-                }
-                @Override
-                public void onProcessed(int fingerprintId) {
-                    if (fingerprintId != 0) {
-                        mHandler.obtainMessage(MSG_HIGHLIGHT_FINGERPRINT_ITEM, fingerprintId, 0)
-                                .sendToTarget();
-                    }
-                }
-            });
+            mFingerprintManager.authenticate(null, mAuthCallback, null, 0);
         }
 
         protected void removeFingerprintPreference(int fingerprintId) {
@@ -181,15 +216,15 @@ public class FingerprintSettings extends SettingsActivity {
 
         private void addFingerprintItemPreferences(PreferenceGroup manageFingerprintCategory) {
             manageFingerprintCategory.removeAll();
-            List<FingerprintItem> items = mFingerprintManager.getEnrolledFingerprints();
+            final List<Fingerprint> items = mFingerprintManager.getEnrolledFingerprints();
             final int fingerprintCount = items.size();
             for (int i = 0; i < fingerprintCount; i++) {
-                final FingerprintItem item = items.get(i);
+                final Fingerprint item = items.get(i);
                 FingerprintPreference pref = new FingerprintPreference(
                         manageFingerprintCategory.getContext());
-                pref.setKey(genKey(item.id));
-                pref.setTitle(item.name);
-                pref.setFingerprintItem(item);
+                pref.setKey(genKey(item.getFingerId()));
+                pref.setTitle(item.getName());
+                pref.setFingerprint(item);
                 pref.setPersistent(false);
                 manageFingerprintCategory.addPreference(pref);
                 pref.setOnPreferenceChangeListener(this);
@@ -222,15 +257,14 @@ public class FingerprintSettings extends SettingsActivity {
                 startActivityForResult(intent, ADD_FINGERPRINT_REQUEST);
             } else if (pref instanceof FingerprintPreference) {
                 FingerprintPreference fpref = (FingerprintPreference) pref;
-                final FingerprintItem item =fpref.getFingerprintItem();
-                showRenameDeleteDialog(item.name, pref, item.id);
+                final Fingerprint fp =fpref.getFingerprint();
+                showRenameDeleteDialog(pref, fp);
                 return super.onPreferenceTreeClick(preferenceScreen, pref);
             }
             return true;
         }
 
-        private void showRenameDeleteDialog(final CharSequence name, Preference pref,
-                final int fpId) {
+        private void showRenameDeleteDialog(Preference pref, final Fingerprint fp) {
             final Activity activity = getActivity();
             AlertDialog dialog = new AlertDialog.Builder(activity)
                     .setView(R.layout.fingerprint_rename_dialog)
@@ -238,10 +272,11 @@ public class FingerprintSettings extends SettingsActivity {
                             new DialogInterface.OnClickListener() {
                                 @Override
                                 public void onClick(DialogInterface dialog, int which) {
-                                    String newName = mDialogTextField.getText().toString();
+                                    final String newName = mDialogTextField.getText().toString();
+                                    final CharSequence name = fp.getName();
                                     if (!newName.equals(name)) {
-                                        Log.v(TAG, "Would rename " + name + " to " + newName);
-                                        mFingerprintManager.rename(fpId, newName);
+                                        if (DEBUG) Log.v(TAG, "rename " + name + " to " + newName);
+                                        mFingerprintManager.rename(fp.getFingerId(), newName);
                                     }
                                     dialog.dismiss();
                                 }
@@ -250,15 +285,15 @@ public class FingerprintSettings extends SettingsActivity {
                             new DialogInterface.OnClickListener() {
                                 @Override
                                 public void onClick(DialogInterface dialog, int which) {
-                                    Log.v(TAG, "Removing fpId " + fpId);
-                                    mFingerprintManager.remove(fpId);
+                                    if (DEBUG) Log.v(TAG, "Removing fpId=" + fp.getFingerId());
+                                    mFingerprintManager.remove(fp, mRemoveCallback);
                                     dialog.dismiss();
                                 }
                             })
                     .create();
             dialog.show();
             mDialogTextField = (EditText) dialog.findViewById(R.id.fingerprint_rename_field);
-            mDialogTextField.setText(name);
+            mDialogTextField.setText(fp.getName());
             mDialogTextField.selectAll();
         }
 
@@ -282,7 +317,7 @@ public class FingerprintSettings extends SettingsActivity {
 
     public static class FingerprintPreference extends Preference {
         private static final int RESET_HIGHLIGHT_DELAY_MS = 500;
-        private FingerprintItem mFingerprintItem;
+        private Fingerprint mFingerprint;
         private View mView;
         private Drawable mHighlightDrawable;
         private Context mContext;
@@ -304,12 +339,12 @@ public class FingerprintSettings extends SettingsActivity {
             this(context, null);
         }
 
-        public void setFingerprintItem(FingerprintItem item) {
-            mFingerprintItem = item;
+        public void setFingerprint(Fingerprint item) {
+            mFingerprint = item;
         }
 
-        public FingerprintItem getFingerprintItem() {
-            return mFingerprintItem;
+        public Fingerprint getFingerprint() {
+            return mFingerprint;
         }
 
         private Drawable getHighlightDrawable() {
index 1f6d50a..4ca2140 100644 (file)
@@ -40,8 +40,8 @@ import android.preference.PreferenceScreen;
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
 import android.security.KeyStore;
+import android.service.fingerprint.Fingerprint;
 import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManager.FingerprintItem;
 import android.service.trust.TrustAgentService;
 import android.telephony.TelephonyManager;
 import android.telephony.SubscriptionManager;
@@ -341,8 +341,8 @@ public class SecuritySettings extends SettingsPreferenceFragment
         fingerprintPreference.setKey(KEY_FINGERPRINT_SETTINGS);
         fingerprintPreference.setTitle(R.string.security_settings_fingerprint_preference_title);
         Intent intent = new Intent();
-        List<FingerprintItem> items = fpm.getEnrolledFingerprints();
-        int fingerprintCount = items.size();
+        final List<Fingerprint> items = fpm.getEnrolledFingerprints();
+        final int fingerprintCount = items != null ? items.size() : 0;
         final String clazz;
         if (fingerprintCount > 0) {
             fingerprintPreference.setSummary(getResources().getQuantityString(