Ask password when user adds a new fingerprint including a checkbox to ask that if they want to use fingerprints in the future and stores it as shared prefernces. Including some refactoring. - Keep the purchase button visible after a successful purchase so that users of the app can test a flow after registering a new fingerprint. - Fixed broken tests. - Use end/start instead of left/right for RTL languages. Bug: 21655960 Change-Id: I9b0015fa5f61048c611ab798afbf96edbc3239eb
diff --git a/security/FingerprintDialog/Application/src/main/AndroidManifest.xml b/security/FingerprintDialog/Application/src/main/AndroidManifest.xml index 5f754ad..3b19fbe 100644 --- a/security/FingerprintDialog/Application/src/main/AndroidManifest.xml +++ b/security/FingerprintDialog/Application/src/main/AndroidManifest.xml
@@ -35,7 +35,9 @@ <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> + + <activity + android:name=".SettingsActivity" + android:label="@string/action_settings" /> </application> - - </manifest>
diff --git a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.java b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.java index 57c00de..8909f75 100644 --- a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.java +++ b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintAuthenticationDialogFragment.java
@@ -17,6 +17,7 @@ package com.example.android.fingerprintdialog; import android.app.DialogFragment; +import android.content.SharedPreferences; import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.view.KeyEvent; @@ -26,6 +27,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.Button; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; @@ -44,6 +46,9 @@ private View mFingerprintContent; private View mBackupContent; private EditText mPassword; + private CheckBox mUseFingerprintFutureCheckBox; + private TextView mPasswordDescriptionTextView; + private TextView mNewFingerprintEnrolledTextView; private Stage mStage = Stage.FINGERPRINT; @@ -52,6 +57,7 @@ @Inject FingerprintUiHelper.FingerprintUiHelperBuilder mFingerprintUiHelperBuilder; @Inject InputMethodManager mInputMethodManager; + @Inject SharedPreferences mSharedPreferences; @Inject public FingerprintAuthenticationDialogFragment() {} @@ -93,6 +99,11 @@ mBackupContent = v.findViewById(R.id.backup_container); mPassword = (EditText) v.findViewById(R.id.password); mPassword.setOnEditorActionListener(this); + mPasswordDescriptionTextView = (TextView) v.findViewById(R.id.password_description); + mUseFingerprintFutureCheckBox = (CheckBox) + v.findViewById(R.id.use_fingerprint_in_future_check); + mNewFingerprintEnrolledTextView = (TextView) + v.findViewById(R.id.new_fingerprint_enrolled_description); mFingerprintUiHelper = mFingerprintUiHelperBuilder.build( (ImageView) v.findViewById(R.id.fingerprint_icon), (TextView) v.findViewById(R.id.fingerprint_status), this); @@ -114,6 +125,10 @@ } } + public void setStage(Stage stage) { + mStage = stage; + } + @Override public void onPause() { super.onPause(); @@ -149,12 +164,25 @@ * let's the activity know about the result. */ private void verifyPassword() { - if (checkPassword(mPassword.getText().toString())) { - ((MainActivity) getActivity()).onPurchased(false /* without Fingerprint */); - dismiss(); - } else { - // assume the password is always correct. + if (!checkPassword(mPassword.getText().toString())) { + return; } + MainActivity activity = ((MainActivity) getActivity()); + if (mStage == Stage.NEW_FINGERPRINT_ENROLLED) { + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(getString(R.string.use_fingerprint_to_authenticate_key), + mUseFingerprintFutureCheckBox.isChecked()); + editor.apply(); + + if (mUseFingerprintFutureCheckBox.isChecked()) { + // Re-create the key so that fingerprints including new ones are validated. + activity.createKey(); + mStage = Stage.FINGERPRINT; + } + } + mPassword.setText(""); + ((MainActivity) getActivity()).onPurchased(false /* without Fingerprint */); + dismiss(); } /** @@ -181,11 +209,18 @@ mFingerprintContent.setVisibility(View.VISIBLE); mBackupContent.setVisibility(View.GONE); break; + case NEW_FINGERPRINT_ENROLLED: + // Intentional fall through case PASSWORD: mCancelButton.setText(R.string.cancel); mSecondDialogButton.setText(R.string.ok); mFingerprintContent.setVisibility(View.GONE); mBackupContent.setVisibility(View.VISIBLE); + if (mStage == Stage.NEW_FINGERPRINT_ENROLLED) { + mPasswordDescriptionTextView.setVisibility(View.GONE); + mNewFingerprintEnrolledTextView.setVisibility(View.VISIBLE); + mUseFingerprintFutureCheckBox.setVisibility(View.VISIBLE); + } break; } } @@ -215,8 +250,9 @@ /** * Enumeration to indicate which authentication method the user is trying to authenticate with. */ - private enum Stage { + public enum Stage { FINGERPRINT, + NEW_FINGERPRINT_ENROLLED, PASSWORD } }
diff --git a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintModule.java b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintModule.java index 16d5067..964e1f6 100644 --- a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintModule.java +++ b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintModule.java
@@ -18,7 +18,10 @@ import android.app.KeyguardManager; import android.content.Context; +import android.content.SharedPreferences; import android.hardware.fingerprint.FingerprintManager; +import android.preference.PreferenceManager; +import android.security.keystore.KeyProperties; import android.view.inputmethod.InputMethodManager; import java.security.KeyStore; @@ -75,7 +78,7 @@ @Provides public KeyGenerator providesKeyGenerator() { try { - return KeyGenerator.getInstance("AES", "AndroidKeyStore"); + return KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"); } catch (NoSuchAlgorithmException | NoSuchProviderException e) { throw new RuntimeException("Failed to get an instance of KeyGenerator", e); } @@ -84,7 +87,9 @@ @Provides public Cipher providesCipher(KeyStore keyStore) { try { - return Cipher.getInstance("AES/CBC/PKCS7Padding"); + return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + + KeyProperties.BLOCK_MODE_CBC + "/" + + KeyProperties.ENCRYPTION_PADDING_PKCS7); } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { throw new RuntimeException("Failed to get an instance of Cipher", e); } @@ -94,4 +99,9 @@ public InputMethodManager providesInputMethodManager(Context context) { return (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); } + + @Provides + public SharedPreferences providesSharedPreferences(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context); + } }
diff --git a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.java b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.java index 6d31ddc..92fcdb1 100644 --- a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.java +++ b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/FingerprintUiHelper.java
@@ -82,7 +82,8 @@ } mCancellationSignal = new CancellationSignal(); mSelfCancelled = false; - mFingerprintManager.authenticate(cryptoObject, mCancellationSignal, 0 /* flags */, this, null); + mFingerprintManager + .authenticate(cryptoObject, mCancellationSignal, 0 /* flags */, this, null); mIcon.setImageResource(R.drawable.ic_fp_40px); }
diff --git a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java index 9d09765..208fd17 100644 --- a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java +++ b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/MainActivity.java
@@ -19,6 +19,8 @@ import android.Manifest; import android.app.Activity; import android.app.KeyguardManager; +import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; @@ -27,6 +29,8 @@ import android.security.keystore.KeyProperties; import android.util.Base64; import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -60,23 +64,28 @@ /** Alias for our key in the Android Key Store */ private static final String KEY_NAME = "my_key"; + private static final int FINGERPRINT_PERMISSION_REQUEST_CODE = 0; + @Inject KeyguardManager mKeyguardManager; @Inject FingerprintAuthenticationDialogFragment mFragment; @Inject KeyStore mKeyStore; @Inject KeyGenerator mKeyGenerator; @Inject Cipher mCipher; + @Inject SharedPreferences mSharedPreferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((InjectedApplication) getApplication()).inject(this); - requestPermissions(new String[]{Manifest.permission.USE_FINGERPRINT}, 0); + requestPermissions(new String[]{Manifest.permission.USE_FINGERPRINT}, + FINGERPRINT_PERMISSION_REQUEST_CODE); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] state) { - if (requestCode == 0 && state[0] == PackageManager.PERMISSION_GRANTED) { + if (requestCode == FINGERPRINT_PERMISSION_REQUEST_CODE + && state[0] == PackageManager.PERMISSION_GRANTED) { setContentView(R.layout.activity_main); Button purchaseButton = (Button) findViewById(R.id.purchase_button); if (!mKeyguardManager.isKeyguardSecure()) { @@ -86,37 +95,63 @@ + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint", Toast.LENGTH_LONG).show(); purchaseButton.setEnabled(false); - return; } createKey(); purchaseButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + findViewById(R.id.confirmation_message).setVisibility(View.GONE); + findViewById(R.id.encrypted_message).setVisibility(View.GONE); - // Show the fingerprint dialog. The user has the option to use the fingerprint with - // crypto, or you can fall back to using a server-side verified password. - mFragment.setCryptoObject(new FingerprintManager.CryptoObject(mCipher)); - mFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG); + // Set up the crypto object for later. The object will be authenticated by use + // of the fingerprint. + if (initCipher()) { + + // Show the fingerprint dialog. The user has the option to use the fingerprint with + // crypto, or you can fall back to using a server-side verified password. + mFragment.setCryptoObject(new FingerprintManager.CryptoObject(mCipher)); + boolean useFingerprintPreference = mSharedPreferences + .getBoolean(getString(R.string.use_fingerprint_to_authenticate_key), + true); + if (useFingerprintPreference) { + mFragment.setStage( + FingerprintAuthenticationDialogFragment.Stage.FINGERPRINT); + } else { + mFragment.setStage( + FingerprintAuthenticationDialogFragment.Stage.PASSWORD); + } + mFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG); + } else { + // This happens if the lock screen has been disabled or or a fingerprint got + // enrolled. Thus show the dialog to authenticate with their password first + // and ask the user if they want to authenticate with fingerprints in the + // future + mFragment.setCryptoObject(new FingerprintManager.CryptoObject(mCipher)); + mFragment.setStage( + FingerprintAuthenticationDialogFragment.Stage.NEW_FINGERPRINT_ENROLLED); + mFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG); + } } }); - - // Set up the crypto object for later. The object will be authenticated by use - // of the fingerprint. - initCipher(); } } - private void initCipher() { + /** + * Initialize the {@link Cipher} instance with the created key in the {@link #createKey()} + * method. + * + * @return {@code true} if initialization is successful, {@code false} if the lock screen has + * been disabled or reset after the key was generated, or if a fingerprint got enrolled after + * the key was generated. + */ + private boolean initCipher() { try { mKeyStore.load(null); SecretKey key = (SecretKey) mKeyStore.getKey(KEY_NAME, null); mCipher.init(Cipher.ENCRYPT_MODE, key); + return true; } catch (KeyPermanentlyInvalidatedException e) { - // This happens if the lock screen has been disabled or reset after the key was - // generated, or if a fingerprint got enrolled after the key was generated. - Toast.makeText(this, "Keys are invalidated after created. Retry the purchase\n" - + e.getMessage(), - Toast.LENGTH_LONG).show(); + return false; } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException | NoSuchAlgorithmException | InvalidKeyException e) { throw new RuntimeException("Failed to init Cipher", e); @@ -124,7 +159,6 @@ } public void onPurchased(boolean withFingerprint) { - findViewById(R.id.purchase_button).setVisibility(View.GONE); if (withFingerprint) { // If the user has authenticated with fingerprint, verify that using cryptography and // then show the confirmation message. @@ -164,7 +198,7 @@ * Creates a symmetric key in the Android Key Store which can only be used after the user has * authenticated with fingerprint. */ - private void createKey() { + public void createKey() { // The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint // for your flow. Use of keys is necessary if you need to know if the set of // enrolled fingerprints has changed. @@ -187,4 +221,22 @@ throw new RuntimeException(e); } } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id == R.id.action_settings) { + Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + return true; + } + return super.onOptionsItemSelected(item); + } }
diff --git a/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.java b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.java new file mode 100644 index 0000000..08b3911 --- /dev/null +++ b/security/FingerprintDialog/Application/src/main/java/com/example/android/fingerprintdialog/SettingsActivity.java
@@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.example.android.fingerprintdialog; + +import android.app.Activity; +import android.os.Bundle; +import android.preference.PreferenceFragment; + +public class SettingsActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Display the fragment as the main content. + getFragmentManager().beginTransaction().replace(android.R.id.content, + new SettingsFragment()).commit(); + } + + /** + * Fragment for settings. + */ + public static class SettingsFragment extends PreferenceFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } + } +} + +
diff --git a/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_backup.xml b/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_backup.xml index 0b88e33..2be05b1 100644 --- a/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_backup.xml +++ b/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_backup.xml
@@ -16,21 +16,37 @@ --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/backup_container" - android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_width="match_parent" + android:layout_height="match_parent" android:paddingTop="16dp" android:paddingBottom="8dp"> - <TextView + <FrameLayout + android:id="@+id/description" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="@android:style/TextAppearance.Material.Subhead" - android:text="@string/password_description" - android:id="@+id/description" android:layout_alignParentTop="true" android:layout_alignParentStart="true" android:layout_marginStart="24dp" android:layout_marginEnd="24dp" - android:textColor="?android:attr/textColorSecondary"/> + > + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:text="@string/password_description" + android:id="@+id/password_description" + android:textColor="?android:attr/textColorSecondary" /> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:text="@string/new_fingerprint_enrolled_description" + android:id="@+id/new_fingerprint_enrolled_description" + android:visibility="gone" + android:textColor="?android:attr/textColorSecondary" /> + </FrameLayout> <EditText android:layout_width="wrap_content" @@ -46,4 +62,17 @@ android:layout_marginEnd="20dp" android:layout_alignParentStart="true" /> + <CheckBox + android:id="@+id/use_fingerprint_in_future_check" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@+id/password" + android:layout_alignParentStart="true" + android:layout_marginTop="16dp" + android:layout_marginStart="20dp" + android:layout_marginEnd="20dp" + android:checked="true" + android:visibility="gone" + android:text="@string/use_fingerprint_in_future" /> + </RelativeLayout> \ No newline at end of file
diff --git a/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_content.xml b/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_content.xml index b56ccbb..3929eba 100644 --- a/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_content.xml +++ b/security/FingerprintDialog/Application/src/main/res/layout/fingerprint_dialog_content.xml
@@ -19,8 +19,8 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="8dp" - android:paddingLeft="24dp" - android:paddingRight="24dp" + android:paddingStart="24dp" + android:paddingEnd="24dp" android:paddingTop="16dp"> <TextView @@ -50,7 +50,7 @@ android:layout_height="wrap_content" android:layout_alignBottom="@+id/fingerprint_icon" android:layout_alignTop="@+id/fingerprint_icon" - android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" android:layout_toEndOf="@+id/fingerprint_icon" android:gravity="center_vertical" android:text="@string/fingerprint_hint"
diff --git a/security/FingerprintDialog/Application/src/main/res/menu/menu_main.xml b/security/FingerprintDialog/Application/src/main/res/menu/menu_main.xml new file mode 100644 index 0000000..73f5e89 --- /dev/null +++ b/security/FingerprintDialog/Application/src/main/res/menu/menu_main.xml
@@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2015 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"> + <item android:id="@+id/action_settings" android:title="@string/action_settings" + android:orderInCategory="100" android:showAsAction="never" /> +</menu>
diff --git a/security/FingerprintDialog/Application/src/main/res/values/strings.xml b/security/FingerprintDialog/Application/src/main/res/values/strings.xml index 8a6ecde..9f5a6fd 100644 --- a/security/FingerprintDialog/Application/src/main/res/values/strings.xml +++ b/security/FingerprintDialog/Application/src/main/res/values/strings.xml
@@ -31,4 +31,8 @@ <string name="item_price">$62.68</string> <string name="item_description">Mesh backpack in white. Black textile trim throughout.</string> <string name="purchase_done">Purchase successful</string> + <string name="new_fingerprint_enrolled_description">A new fingerprint was added to this device, so your password is required.</string> + <string name="use_fingerprint_in_future">Use fingerprint in the future</string> + <string name="use_fingerprint_to_authenticate_title">Use fingerprint to authenticate</string> + <string name="use_fingerprint_to_authenticate_key" >use_fingerprint_to_authenticate_key</string> </resources>
diff --git a/security/FingerprintDialog/Application/src/main/res/xml/preferences.xml b/security/FingerprintDialog/Application/src/main/res/xml/preferences.xml new file mode 100644 index 0000000..761391d --- /dev/null +++ b/security/FingerprintDialog/Application/src/main/res/xml/preferences.xml
@@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2015 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> + <CheckBoxPreference + android:key="@string/use_fingerprint_to_authenticate_key" + android:title="@string/use_fingerprint_to_authenticate_title" + android:persistent="true" + android:defaultValue="true" /> +</PreferenceScreen> \ No newline at end of file
diff --git a/security/FingerprintDialog/Application/src/test/java/com/example/android/fingerprintdialog/FingerprintUiHelperTest.java b/security/FingerprintDialog/Application/src/test/java/com/example/android/fingerprintdialog/FingerprintUiHelperTest.java index 9a68ee7..da9b2a3 100644 --- a/security/FingerprintDialog/Application/src/test/java/com/example/android/fingerprintdialog/FingerprintUiHelperTest.java +++ b/security/FingerprintDialog/Application/src/test/java/com/example/android/fingerprintdialog/FingerprintUiHelperTest.java
@@ -12,6 +12,7 @@ import android.content.res.Resources; import android.hardware.fingerprint.FingerprintManager; import android.os.CancellationSignal; +import android.os.Handler; import android.widget.ImageView; import android.widget.TextView; @@ -59,8 +60,9 @@ public void testStartListening_fingerprintAuthAvailable() { mFingerprintUiHelper.startListening(mockCryptoObject); - verify(mockFingerprintManager).authenticate(eq(mockCryptoObject), eq(0), - isA(CancellationSignal.class), eq(mFingerprintUiHelper), any(Handler.class)); + verify(mockFingerprintManager).authenticate(eq(mockCryptoObject), + isA(CancellationSignal.class), eq(0), eq(mFingerprintUiHelper), + any(Handler.class)); verify(mockIcon).setImageResource(R.drawable.ic_fp_40px); } @@ -71,8 +73,8 @@ mFingerprintUiHelper.startListening(mockCryptoObject); verify(mockFingerprintManager, never()).authenticate( - any(FingerprintManager.CryptoObject.class), eq(0), - any(CancellationSignal.class), any(FingerprintUiHelper.class), any(Handler.class)); + any(FingerprintManager.CryptoObject.class), any(CancellationSignal.class), eq(0), + any(FingerprintUiHelper.class), any(Handler.class)); } @Test
diff --git a/security/FingerprintDialog/screenshots/4-new-fingerprint-enrolled.png b/security/FingerprintDialog/screenshots/4-new-fingerprint-enrolled.png new file mode 100644 index 0000000..7dcf080 --- /dev/null +++ b/security/FingerprintDialog/screenshots/4-new-fingerprint-enrolled.png Binary files differ
diff --git a/security/FingerprintDialog/template-params.xml b/security/FingerprintDialog/template-params.xml index 3916c57..ab392ea 100644 --- a/security/FingerprintDialog/template-params.xml +++ b/security/FingerprintDialog/template-params.xml
@@ -61,6 +61,7 @@ <img>screenshots/1-purchase-screen.png</img> <img>screenshots/2-fingerprint-dialog.png</img> <img>screenshots/3-fingerprint-authenticated.png</img> + <img>screenshots/4-new-fingerprint-enrolled.png</img> </screenshots> <api_refs>