diff options
author | 2021-08-23 19:29:17 +0000 | |
---|---|---|
committer | 2021-08-23 19:29:17 +0000 | |
commit | 001ec6038a696f61a77de0ebc3112587371a0163 (patch) | |
tree | 18d7cd392fe0689d7e4f5cc9913f5c793846a64c | |
parent | ba2546df4cfa0257cdd0bfb2c35bc6c4ae1cb487 (diff) | |
parent | 199da10111ae543dd3ed6f7a098cbc458d1e39c5 (diff) |
Merge "Update lock icon location if auth setup is delayed" into sc-qpr1-dev
4 files changed, 213 insertions, 7 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java index edb05691b530..dd3bb8990599 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java @@ -27,6 +27,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; import com.android.settingslib.Utils; import com.android.systemui.Dumpable; @@ -79,7 +80,11 @@ public class LockIconView extends FrameLayout implements Dumpable { mLockIcon.setImageDrawable(drawable); } - void setCenterLocation(@NonNull PointF center, int radius) { + /** + * Set the location of the lock icon. + */ + @VisibleForTesting + public void setCenterLocation(@NonNull PointF center, int radius) { mLockIconCenter = center; mRadius = radius; diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java index aa8cbd710e90..47f0714af164 100644 --- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java @@ -68,7 +68,8 @@ import javax.inject.Inject; /** * Controls when to show the LockIcon affordance (lock/unlocked icon or circle) on lock screen. * - * This view will only be shown if the user has UDFPS or FaceAuth enrolled + * For devices with UDFPS, the lock icon will show at the sensor location. Else, the lock + * icon will show a set distance from the bottom of the device. */ @StatusBarComponent.StatusBarScope public class LockIconViewController extends ViewController<LockIconView> implements Dumpable { @@ -172,15 +173,14 @@ public class LockIconViewController extends ViewController<LockIconView> impleme @Override protected void onInit() { + mAuthController.addCallback(mAuthControllerCallback); + mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; + mView.setAccessibilityDelegate(mAccessibilityDelegate); } @Override protected void onViewAttached() { - // we check this here instead of onInit since the FingerprintManager + FaceManager may not - // have started up yet onInit - mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; - updateConfiguration(); updateKeyguardShowing(); mUserUnlockedWithBiometric = false; @@ -584,4 +584,12 @@ public class LockIconViewController extends ViewController<LockIconView> impleme public void setAlpha(float alpha) { mView.setAlpha(alpha); } + + private final AuthController.Callback mAuthControllerCallback = new AuthController.Callback() { + @Override + public void onAllAuthenticatorsRegistered() { + mUdfpsSupported = mAuthController.getUdfpsSensorLocation() != null; + updateConfiguration(); + } + }; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index 0ce1846e7745..ab5f2b8289be 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -786,7 +786,11 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, .build(sensorIds, credentialAllowed, mFpProps, mFaceProps); } - interface Callback { + /** + * AuthController callback used to receive signal for when biometric authenticators are + * registered. + */ + public interface Callback { /** * Called when authenticators are registered. If authenticators are already * registered before this call, this callback will never be triggered. diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java new file mode 100644 index 000000000000..d279bbb02cee --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2021 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.systemui.keyguard; + +import static junit.framework.Assert.assertEquals; + +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.PointF; +import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; +import android.os.Vibrator; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.util.DisplayMetrics; +import android.view.View; +import android.view.accessibility.AccessibilityManager; + +import androidx.test.filters.SmallTest; + +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardViewController; +import com.android.keyguard.LockIconView; +import com.android.keyguard.LockIconViewController; +import com.android.systemui.SysuiTestCase; +import com.android.systemui.biometrics.AuthController; +import com.android.systemui.biometrics.AuthRippleController; +import com.android.systemui.dump.DumpManager; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.concurrency.DelayableExecutor; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; +import java.util.List; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class LockIconViewControllerTest extends SysuiTestCase { + private @Mock LockIconView mLockIconView; + private @Mock Context mContext; + private @Mock Resources mResources; + private @Mock DisplayMetrics mDisplayMetrics; + private @Mock StatusBarStateController mStatusBarStateController; + private @Mock KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private @Mock KeyguardViewController mKeyguardViewController; + private @Mock KeyguardStateController mKeyguardStateController; + private @Mock FalsingManager mFalsingManager; + private @Mock AuthController mAuthController; + private @Mock DumpManager mDumpManager; + private @Mock AccessibilityManager mAccessibilityManager; + private @Mock ConfigurationController mConfigurationController; + private @Mock DelayableExecutor mDelayableExecutor; + private @Mock Vibrator mVibrator; + private @Mock AuthRippleController mAuthRippleController; + + private LockIconViewController mLockIconViewController; + + // Capture listeners so that they can be used to send events + @Captor private ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor = + ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class); + private View.OnAttachStateChangeListener mAttachListener; + + @Captor private ArgumentCaptor<AuthController.Callback> mAuthControllerCallbackCaptor; + private AuthController.Callback mAuthControllerCallback; + + @Captor private ArgumentCaptor<PointF> mPointCaptor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + when(mLockIconView.getResources()).thenReturn(mResources); + when(mLockIconView.getContext()).thenReturn(mContext); + when(mContext.getResources()).thenReturn(mResources); + when(mResources.getDisplayMetrics()).thenReturn(mDisplayMetrics); + + mLockIconViewController = new LockIconViewController( + mLockIconView, + mStatusBarStateController, + mKeyguardUpdateMonitor, + mKeyguardViewController, + mKeyguardStateController, + mFalsingManager, + mAuthController, + mDumpManager, + mAccessibilityManager, + mConfigurationController, + mDelayableExecutor, + mVibrator, + mAuthRippleController + ); + } + + @Test + public void testUpdateFingerprintLocationOnInit() { + // GIVEN fp sensor location is available pre-init + final PointF udfpsLocation = new PointF(50, 75); + final int radius = 33; + final FingerprintSensorPropertiesInternal fpProps = + new FingerprintSensorPropertiesInternal( + /* sensorId */ 0, + /* strength */ 0, + /* max enrollments per user */ 5, + /* component info */ new ArrayList<>(), + /* sensorType */ 3, + /* resetLockoutRequiresHwToken */ false, + (int) udfpsLocation.x, (int) udfpsLocation.y, radius); + when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation); + when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps)); + + // WHEN lock icon view controller is initialized and attached + mLockIconViewController.init(); + captureAttachListener(); + mAttachListener.onViewAttachedToWindow(null); + + // THEN lock icon view location is updated with the same coordinates as fpProps + verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius)); + assertEquals(udfpsLocation, mPointCaptor.getValue()); + } + + @Test + public void testUpdateFingerprintLocationOnAuthenticatorsRegistered() { + // GIVEN fp sensor location is not available pre-init + when(mAuthController.getFingerprintSensorLocation()).thenReturn(null); + when(mAuthController.getUdfpsProps()).thenReturn(null); + mLockIconViewController.init(); + + // GIVEN fp sensor location is available post-init + captureAuthControllerCallback(); + final PointF udfpsLocation = new PointF(50, 75); + final int radius = 33; + final FingerprintSensorPropertiesInternal fpProps = + new FingerprintSensorPropertiesInternal( + /* sensorId */ 0, + /* strength */ 0, + /* max enrollments per user */ 5, + /* component info */ new ArrayList<>(), + /* sensorType */ 3, + /* resetLockoutRequiresHwToken */ false, + (int) udfpsLocation.x, (int) udfpsLocation.y, radius); + when(mAuthController.getUdfpsSensorLocation()).thenReturn(udfpsLocation); + when(mAuthController.getUdfpsProps()).thenReturn(List.of(fpProps)); + + // WHEN all authenticators are registered + mAuthControllerCallback.onAllAuthenticatorsRegistered(); + + // THEN lock icon view location is updated with the same coordinates as fpProps + verify(mLockIconView).setCenterLocation(mPointCaptor.capture(), eq(radius)); + assertEquals(udfpsLocation, mPointCaptor.getValue()); + } + + private void captureAuthControllerCallback() { + verify(mAuthController).addCallback(mAuthControllerCallbackCaptor.capture()); + mAuthControllerCallback = mAuthControllerCallbackCaptor.getValue(); + } + + private void captureAttachListener() { + verify(mLockIconView).addOnAttachStateChangeListener(mAttachCaptor.capture()); + mAttachListener = mAttachCaptor.getValue(); + } +} |