diff --git a/res/values/strings.xml b/res/values/strings.xml index 04852e0b64c..5f5d58ea283 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -893,6 +893,12 @@ Use your face to Unlock your device + + App sign-in \u0026 payments + + Eyes open to unlock + + When using face authentication, your eyes must be open Remove face data @@ -6949,7 +6955,7 @@ pay, tap, payments backup, back up gesture - face, unlock + face, unlock, auth, sign in imei, meid, min, prl version, imei sv network, mobile network state, service state, signal strength, mobile network type, roaming, iccid serial number, hardware version diff --git a/res/xml/security_settings_face.xml b/res/xml/security_settings_face.xml index 3dfcfd77413..2bdfdc80e24 100644 --- a/res/xml/security_settings_face.xml +++ b/res/xml/security_settings_face.xml @@ -22,21 +22,34 @@ + app:preview="@drawable/face_enroll_introduction" + app:controller="com.android.settings.widget.VideoPreferenceController"/> + app:controller="com.android.settings.biometrics.face.FaceSettingsKeyguardPreferenceController"/> + + + diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index c718ddea5aa..748f874813b 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -104,7 +104,7 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { if (mFaceManager == null) { return 0; } - return mFaceManager.preEnroll(); + return mFaceManager.generateChallenge(); } @Override diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index 4944c7f6beb..d7dc9f866fd 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -16,11 +16,16 @@ package com.android.settings.biometrics.face; +import static android.app.Activity.RESULT_OK; + import static com.android.settings.biometrics.BiometricEnrollBase.CONFIRM_REQUEST; +import static com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED; import android.content.Context; +import android.content.Intent; import android.hardware.face.FaceManager; import android.os.Bundle; +import android.os.UserHandle; import android.provider.SearchIndexableResource; import android.util.Log; @@ -30,6 +35,7 @@ import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.widget.VideoPreferenceController; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.search.SearchIndexable; @@ -47,7 +53,11 @@ public class FaceSettings extends DashboardFragment { private static final String TAG = "FaceSettings"; private static final String KEY_LAUNCHED_CONFIRM = "key_launched_confirm"; + private FaceManager mFaceManager; + private int mUserId; private boolean mLaunchedConfirm; + private byte[] mToken; + private FaceSettingsAttentionPreferenceController mAttentionController; public static boolean isAvailable(Context context) { FaceManager manager = Utils.getFaceManagerOrNull(context); @@ -79,31 +89,80 @@ public class FaceSettings extends DashboardFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mFaceManager = getPrefContext().getSystemService(FaceManager.class); + mUserId = getActivity().getIntent().getIntExtra( + Intent.EXTRA_USER_ID, UserHandle.myUserId()); + if (savedInstanceState != null) { mLaunchedConfirm = savedInstanceState.getBoolean(KEY_LAUNCHED_CONFIRM, false); } if (!mLaunchedConfirm) { + final long challenge = mFaceManager.generateChallenge(); ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this); if (!helper.launchConfirmationActivity(CONFIRM_REQUEST, - getString(R.string.security_settings_face_preference_title))) { + getString(R.string.security_settings_face_preference_title), + null, null, challenge, mUserId)) { Log.e(TAG, "Password not set"); finish(); } } } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == CONFIRM_REQUEST) { + if (resultCode == RESULT_FINISHED || resultCode == RESULT_OK) { + // The pin/pattern/password was set. + if (data != null) { + mToken = data.getByteArrayExtra( + ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); + if (mToken != null) { + mAttentionController.setToken(mToken); + } + } + } + } + + if (mToken == null) { + // Didn't get an authentication, finishing + getActivity().finish(); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (getActivity().isFinishing()) { + final int result = mFaceManager.revokeChallenge(); + if (result < 0) { + Log.w(TAG, "revokeChallenge failed, result: " + result); + } + } + } + @Override protected List createPreferenceControllers(Context context) { - return buildPreferenceControllers(context, getSettingsLifecycle()); + final List controllers = + buildPreferenceControllers(context, getSettingsLifecycle()); + for (AbstractPreferenceController controller : controllers) { + if (controller instanceof FaceSettingsAttentionPreferenceController) { + mAttentionController = (FaceSettingsAttentionPreferenceController) controller; + break; + } + } + + return controllers; } private static List buildPreferenceControllers(Context context, Lifecycle lifecycle) { final List controllers = new ArrayList<>(); - controllers.add(new FaceSettingsVideoPreferenceController(context)); controllers.add(new FaceSettingsImprovePreferenceController(context)); - controllers.add(new FaceSettingsUnlockPreferenceController(context)); + controllers.add(new FaceSettingsKeyguardPreferenceController(context)); + controllers.add(new FaceSettingsAppPreferenceController(context)); + controllers.add(new FaceSettingsAttentionPreferenceController(context)); controllers.add(new FaceSettingsRemoveButtonPreferenceController(context)); controllers.add(new FaceSettingsFooterPreferenceController(context)); return controllers; diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java new file mode 100644 index 00000000000..038dbd8c84f --- /dev/null +++ b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 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.android.settings.biometrics.face; + +import static android.provider.Settings.Secure.FACE_UNLOCK_APP_ENABLED; + +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.core.TogglePreferenceController; + +/** + * Preference controller for Face settings page controlling the ability to use + * Face authentication in apps (through BiometricPrompt). + */ +public class FaceSettingsAppPreferenceController extends TogglePreferenceController { + + private static final String KEY = "security_settings_face_app"; + + private static final int ON = 1; + private static final int OFF = 0; + private static final int DEFAULT = ON; // face unlock is enabled for BiometricPrompt by default + + public FaceSettingsAppPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + public FaceSettingsAppPreferenceController(Context context) { + this(context, KEY); + } + + @Override + public boolean isChecked() { + if (!FaceSettings.isAvailable(mContext)) { + return false; + } + return Settings.Secure.getInt( + mContext.getContentResolver(), FACE_UNLOCK_APP_ENABLED, DEFAULT) == ON; + } + + @Override + public boolean setChecked(boolean isChecked) { + return Settings.Secure.putInt(mContext.getContentResolver(), FACE_UNLOCK_APP_ENABLED, + isChecked ? ON : OFF); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } +} diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java new file mode 100644 index 00000000000..e26f8813fca --- /dev/null +++ b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 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.android.settings.biometrics.face; + +import android.content.Context; +import android.hardware.face.FaceManager; +import android.util.Log; + +import com.android.settings.core.TogglePreferenceController; + +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +/** + * Preference controller that manages the ability to use face authentication with/without + * user attention. See {@link FaceManager#setRequireAttention(boolean, byte[])}. + */ +public class FaceSettingsAttentionPreferenceController extends TogglePreferenceController { + + public static final String KEY = "security_settings_face_require_attention"; + + private byte[] mToken; + private FaceManager mFaceManager; + private SwitchPreference mPreference; + + public FaceSettingsAttentionPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mFaceManager = context.getSystemService(FaceManager.class); + } + + public FaceSettingsAttentionPreferenceController(Context context) { + this(context, KEY); + } + + public void setToken(byte[] token) { + mToken = token; + mPreference.setChecked(mFaceManager.getRequireAttention(mToken)); + } + + /** + * Displays preference in this controller. + */ + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = (SwitchPreference) screen.findPreference(KEY); + } + + @Override + public boolean isChecked() { + if (!FaceSettings.isAvailable(mContext)) { + return true; + } else if (mToken == null) { + // The token will be null when the controller is first created, since CC has not been + // completed by the user. Once it's completed, FaceSettings will use setToken which + // will retrieve the correct value from FaceService + return true; + } + return mFaceManager.getRequireAttention(mToken); + } + + @Override + public boolean setChecked(boolean isChecked) { + mFaceManager.setRequireAttention(isChecked, mToken); + return true; + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } +} diff --git a/src/com/android/settings/biometrics/face/FaceSettingsUnlockPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java similarity index 89% rename from src/com/android/settings/biometrics/face/FaceSettingsUnlockPreferenceController.java rename to src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java index 5c846461e24..fe7d398d080 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsUnlockPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java @@ -31,19 +31,19 @@ import com.android.settings.core.TogglePreferenceController; * Preference controller for Face settings page controlling the ability to unlock the phone * with face. */ -public class FaceSettingsUnlockPreferenceController extends TogglePreferenceController { +public class FaceSettingsKeyguardPreferenceController extends TogglePreferenceController { - private static final String KEY = "security_settings_face_unlock"; + private static final String KEY = "security_settings_face_keyguard"; private static final int ON = 1; private static final int OFF = 0; private static final int DEFAULT = ON; // face unlock is enabled on keyguard by default - public FaceSettingsUnlockPreferenceController(Context context, String preferenceKey) { + public FaceSettingsKeyguardPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); } - public FaceSettingsUnlockPreferenceController(Context context) { + public FaceSettingsKeyguardPreferenceController(Context context) { this(context, KEY); } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsVideoPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsVideoPreferenceController.java deleted file mode 100644 index 6fbb9c4f024..00000000000 --- a/src/com/android/settings/biometrics/face/FaceSettingsVideoPreferenceController.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2018 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.android.settings.biometrics.face; - -import android.content.Context; - -import com.android.settings.core.BasePreferenceController; - -public class FaceSettingsVideoPreferenceController extends BasePreferenceController { - - private static final String PREF_KEY_VIDEO = "security_settings_face_video"; - - public FaceSettingsVideoPreferenceController(Context context, - String preferenceKey) { - super(context, preferenceKey); - } - - public FaceSettingsVideoPreferenceController(Context context) { - this(context, PREF_KEY_VIDEO); - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE; - } -} diff --git a/src/com/android/settings/password/SetNewPasswordController.java b/src/com/android/settings/password/SetNewPasswordController.java index d5641cdfafa..bf552718b14 100644 --- a/src/com/android/settings/password/SetNewPasswordController.java +++ b/src/com/android/settings/password/SetNewPasswordController.java @@ -148,7 +148,7 @@ final class SetNewPasswordController { private Bundle getFaceChooseLockExtras() { Bundle chooseLockExtras = new Bundle(); - long challenge = mFaceManager.preEnroll(); + long challenge = mFaceManager.generateChallenge(); chooseLockExtras.putInt(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, PASSWORD_QUALITY_SOMETHING); chooseLockExtras.putBoolean( diff --git a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java index af77ad83a14..67f7b0adc5e 100644 --- a/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java +++ b/tests/robotests/src/com/android/settings/password/SetNewPasswordControllerTest.java @@ -84,7 +84,7 @@ public final class SetNewPasswordControllerTest { when(mFingerprintManager.preEnroll()).thenReturn(FINGERPRINT_CHALLENGE); when(mPackageManager.hasSystemFeature(eq(FEATURE_FINGERPRINT))).thenReturn(true); - when(mFaceManager.preEnroll()).thenReturn(FACE_CHALLENGE); + when(mFaceManager.generateChallenge()).thenReturn(FACE_CHALLENGE); when(mPackageManager.hasSystemFeature(eq(FEATURE_FACE))).thenReturn(true); }