From b0ff672a7e66ebd21a4860d61fb60ccc1764c9ef Mon Sep 17 00:00:00 2001 From: Hao Dong Date: Mon, 27 Mar 2023 20:00:44 +0000 Subject: [PATCH] Post-enroll settings screen shows class 3 strings Test: atest FaceSettingsFooterPreferenceControllerTest Test: manual test Bug: 274959218 Change-Id: I2e30666baf36a48a47e9ed9e4e046cefc805995a --- res-product/values/strings.xml | 24 ++++ res/values/strings.xml | 6 +- ...aceSettingsFooterPreferenceController.java | 57 +++++++- ...ettingsFooterPreferenceControllerTest.java | 135 ++++++++++++++++++ 4 files changed, 210 insertions(+), 12 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceControllerTest.java diff --git a/res-product/values/strings.xml b/res-product/values/strings.xml index 5b6474ef103..3569485bd74 100644 --- a/res-product/values/strings.xml +++ b/res-product/values/strings.xml @@ -155,6 +155,30 @@ + + Use your face to unlock your phone or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your tablet or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the tablet can unlock it when you don\u2019t intend to.\n\nYour tablet can be unlocked by someone else if it\u2019s held up to your face.\n\nYour tablet can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your device or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the device can unlock it when you don\u2019t intend to.\n\nYour device can be unlocked by someone else if it\u2019s held up to your face.\n\nYour device can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your phone or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your tablet or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the tablet can unlock it when you don\u2019t intend to.\n\nYour tablet can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour tablet can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your device or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the device can unlock it when you don\u2019t intend to.\n\nYour device can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour device can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your tablet or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the tablet can unlock it when you don\u2019t intend to.\n\nYour tablet can be unlocked by someone else if it\u2019s held up to your face.\n\nYour tablet can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your device or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the device can unlock it when you don\u2019t intend to.\n\nYour device can be unlocked by someone else if it\u2019s held up to your face.\n\nYour device can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your phone or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your tablet or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the tablet can unlock it when you don\u2019t intend to.\n\nYour tablet can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour tablet can be unlocked by someone who looks a lot like you, like an identical sibling. + + Use your face to unlock your device or verify it\u2019s you, like when you sign in to apps or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the device can unlock it when you don\u2019t intend to.\n\nYour device can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour device can be unlocked by someone who looks a lot like you, like an identical sibling. Use your fingerprint to unlock your %s or verify it\u2019s you, like when you sign in to apps or approve a purchase diff --git a/res/values/strings.xml b/res/values/strings.xml index 44f65034c70..8e6cf230772 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -729,11 +729,7 @@ Delete face model Set up Face Unlock - - Use your face to unlock your phone or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling. - - Use your face to unlock your phone or for authentication in apps, like when you sign in or approve a purchase.\n\nKeep in mind:\nYou can only have one face set up at a time. To add another face, delete the current one.\n\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, like an identical sibling. - + Delete face model? Your face model will be permanently and securely deleted.\n\nAfter deletion, you will need your PIN, pattern, or password to unlock your phone or for authentication in apps. diff --git a/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java index ba1047b0d4d..261166b8647 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceController.java @@ -18,8 +18,15 @@ package com.android.settings.biometrics.face; import android.content.Context; import android.content.Intent; +import android.hardware.biometrics.SensorProperties; +import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; +import android.util.Log; +import androidx.annotation.NonNull; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -27,18 +34,47 @@ import com.android.settings.overlay.FeatureFactory; import com.android.settings.utils.AnnotationSpan; import com.android.settingslib.HelpUtils; +import java.util.List; + /** * Footer for face settings showing the help text and help link. */ public class FaceSettingsFooterPreferenceController extends BasePreferenceController { - + private static final String TAG = "FaceSettingsFooterPreferenceController"; private static final String ANNOTATION_URL = "url"; - - private FaceFeatureProvider mProvider; + private final FaceFeatureProvider mProvider; + private Preference mPreference; + private boolean mIsFaceStrong; public FaceSettingsFooterPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mProvider = FeatureFactory.getFactory(context).getFaceFeatureProvider(); + FaceManager faceManager = context.getSystemService(FaceManager.class); + faceManager.addAuthenticatorsRegisteredCallback( + new IFaceAuthenticatorsRegisteredCallback.Stub() { + @Override + public void onAllAuthenticatorsRegistered( + @NonNull List sensors) { + if (sensors.isEmpty()) { + Log.e(TAG, "No sensors"); + return; + } + + boolean isFaceStrong = sensors.get(0).sensorStrength + == SensorProperties.STRENGTH_STRONG; + if (mIsFaceStrong == isFaceStrong) { + return; + } + mIsFaceStrong = isFaceStrong; + updateState(mPreference); + } + }); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(mPreferenceKey); } @Override @@ -55,10 +91,17 @@ public class FaceSettingsFooterPreferenceController extends BasePreferenceContro final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(mContext, ANNOTATION_URL, helpIntent); - final int footerRes = mProvider.isAttentionSupported(mContext) - ? R.string.security_settings_face_settings_footer - : R.string.security_settings_face_settings_footer_attention_not_supported; - + int footerRes; + boolean isAttentionSupported = mProvider.isAttentionSupported(mContext); + if (mIsFaceStrong) { + footerRes = isAttentionSupported + ? R.string.security_settings_face_settings_footer_class3 + : R.string.security_settings_face_settings_footer_attention_not_supported; + } else { + footerRes = isAttentionSupported + ? R.string.security_settings_face_settings_footer + : R.string.security_settings_face_settings_footer_class3_attention_not_supported; + } preference.setTitle(AnnotationSpan.linkify( mContext.getText(footerRes), linkInfo)); } diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceControllerTest.java new file mode 100644 index 00000000000..bf3d9f70a23 --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsFooterPreferenceControllerTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 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 com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.hardware.face.FaceManager; +import android.hardware.face.FaceSensorProperties; +import android.hardware.face.FaceSensorPropertiesInternal; +import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; +import android.os.Looper; +import android.os.RemoteException; + +import androidx.preference.Preference; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settingslib.widget.FooterPreference; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.shadows.ShadowApplication; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +public class FaceSettingsFooterPreferenceControllerTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + private static final String PREF_KEY = "security_face_footer"; + @Mock + private FaceManager mFaceManager; + @Captor + private ArgumentCaptor mCaptor; + private Preference mPreference; + private Context mContext; + private FaceSettingsFooterPreferenceController mController; + + @Before + public void setUp() { + mContext = spy(RuntimeEnvironment.application); + if (Looper.myLooper() == null) { + Looper.prepare(); // needed to create the preference screen + } + ShadowApplication.getInstance().setSystemService(Context.FACE_SERVICE, mFaceManager); + + mController = new FaceSettingsFooterPreferenceController(mContext, PREF_KEY); + PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext); + mPreference = new FooterPreference(mContext); + mPreference.setKey(PREF_KEY); + screen.addPreference(mPreference); + + mController.displayPreference(screen); + } + + @Test + public void isSliceable_returnFalse() { + assertThat(mController.isSliceable()).isFalse(); + } + + @Test + public void testString_faceNotClass3() throws RemoteException { + verify(mFaceManager).addAuthenticatorsRegisteredCallback(mCaptor.capture()); + mController.updateState(mPreference); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.security_settings_face_settings_footer)); + + List props = List.of(new FaceSensorPropertiesInternal( + 0 /* id */, + FaceSensorProperties.STRENGTH_WEAK, + 1 /* maxTemplatesAllowed */, + new ArrayList<>() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresChallenge */)); + mCaptor.getValue().onAllAuthenticatorsRegistered(props); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.security_settings_face_settings_footer)); + } + + @Test + public void testString_faceClass3() throws RemoteException { + verify(mFaceManager).addAuthenticatorsRegisteredCallback(mCaptor.capture()); + mController.updateState(mPreference); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.security_settings_face_settings_footer)); + + List props = List.of(new FaceSensorPropertiesInternal( + 0 /* id */, + FaceSensorProperties.STRENGTH_STRONG, + 1 /* maxTemplatesAllowed */, + new ArrayList<>() /* componentInfo */, + FaceSensorProperties.TYPE_UNKNOWN, + true /* supportsFaceDetection */, + true /* supportsSelfIllumination */, + false /* resetLockoutRequiresChallenge */)); + mCaptor.getValue().onAllAuthenticatorsRegistered(props); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.security_settings_face_settings_footer_class3)); + } +}