summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java55
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt117
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java18
7 files changed, 251 insertions, 46 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index badad9d86a0f..71e2bb657de4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -48,10 +48,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
-import android.view.Display;
import android.view.MotionEvent;
-import android.view.OrientationEventListener;
-import android.view.Surface;
import android.view.WindowManager;
import com.android.internal.R;
@@ -72,6 +69,8 @@ import java.util.Set;
import javax.inject.Inject;
import javax.inject.Provider;
+import kotlin.Unit;
+
/**
* Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
* appropriate biometric UI (e.g. BiometricDialogView).
@@ -107,7 +106,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
TaskStackListener mTaskStackListener;
@VisibleForTesting
IBiometricSysuiReceiver mReceiver;
- @NonNull private final BiometricOrientationEventListener mOrientationListener;
+ @VisibleForTesting
+ @NonNull final BiometricOrientationEventListener mOrientationListener;
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
@Nullable private List<FingerprintSensorPropertiesInternal> mFpProps;
@Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
@@ -120,42 +120,6 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
}
}
- private class BiometricOrientationEventListener extends OrientationEventListener {
- @Surface.Rotation private int mLastRotation;
-
- BiometricOrientationEventListener(Context context) {
- super(context);
- mLastRotation = context.getDisplay().getRotation();
- }
-
- @Override
- public void onOrientationChanged(int orientation) {
- if (orientation == ORIENTATION_UNKNOWN) {
- return;
- }
-
- final Display display = mContext.getDisplay();
- if (display == null) {
- return;
- }
-
- final int rotation = display.getRotation();
- if (mLastRotation != rotation) {
- mLastRotation = rotation;
-
- if (mCurrentDialog != null) {
- mCurrentDialog.onOrientationChanged();
- }
- if (mUdfpsController != null) {
- mUdfpsController.onOrientationChanged();
- }
- if (mSidefpsController != null) {
- mSidefpsController.onOrientationChanged();
- }
- }
- }
- }
-
@NonNull
private final IFingerprintAuthenticatorsRegisteredCallback
mFingerprintAuthenticatorsRegisteredCallback =
@@ -468,7 +432,10 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mUdfpsControllerFactory = udfpsControllerFactory;
mSidefpsControllerFactory = sidefpsControllerFactory;
mWindowManager = windowManager;
- mOrientationListener = new BiometricOrientationEventListener(context);
+ mOrientationListener = new BiometricOrientationEventListener(context, () -> {
+ onOrientationChanged();
+ return Unit.INSTANCE;
+ });
mFaceProps = mFaceManager != null ? mFaceManager.getSensorPropertiesInternal() : null;
@@ -790,6 +757,12 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
}
}
+ private void onOrientationChanged() {
+ if (mCurrentDialog != null) {
+ mCurrentDialog.onOrientationChanged();
+ }
+ }
+
protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
boolean skipIntro, long operationId,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt
new file mode 100644
index 000000000000..08ea857eb208
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricOrientationEventListener.kt
@@ -0,0 +1,60 @@
+/*
+ * 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.biometrics
+
+import android.content.Context
+import android.view.OrientationEventListener
+
+/**
+ * An [OrientationEventListener] that invokes the [onOrientationChanged] callback whenever
+ * the orientation of the device has changed in order to keep overlays for biometric sensors
+ * aligned with the device's screen.
+ */
+class BiometricOrientationEventListener(
+ private val context: Context,
+ private val onOrientationChanged: () -> Unit
+) : OrientationEventListener(context) {
+
+ /** If actively listening (not available in base class). */
+ var enabled: Boolean = false
+ private set
+
+ private var lastRotation = context.display?.rotation ?: ORIENTATION_UNKNOWN
+
+ override fun onOrientationChanged(orientation: Int) {
+ if (orientation == ORIENTATION_UNKNOWN) {
+ return
+ }
+
+ val rotation = context.display?.rotation ?: return
+ if (lastRotation != rotation) {
+ lastRotation = rotation
+
+ onOrientationChanged()
+ }
+ }
+
+ override fun enable() {
+ enabled = true
+ super.enable()
+ }
+
+ override fun disable() {
+ enabled = false
+ super.disable()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java
index 436e1e4e3116..a51c2b802b91 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SidefpsController.java
@@ -41,6 +41,8 @@ import com.android.systemui.util.concurrency.DelayableExecutor;
import javax.inject.Inject;
+import kotlin.Unit;
+
/**
* Shows and hides the side fingerprint sensor (side-fps) overlay and handles side fps touch events.
*/
@@ -52,6 +54,8 @@ public class SidefpsController {
private final FingerprintManager mFingerprintManager;
private final WindowManager mWindowManager;
private final DelayableExecutor mFgExecutor;
+ @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
+
// TODO: update mDisplayHeight and mDisplayWidth for multi-display devices
private final int mDisplayHeight;
private final int mDisplayWidth;
@@ -95,6 +99,10 @@ public class SidefpsController {
mFingerprintManager = checkNotNull(fingerprintManager);
mWindowManager = windowManager;
mFgExecutor = fgExecutor;
+ mOrientationListener = new BiometricOrientationEventListener(context, () -> {
+ onOrientationChanged();
+ return Unit.INSTANCE;
+ });
mSensorProps = findFirstSidefps();
checkArgument(mSensorProps != null);
@@ -119,14 +127,15 @@ public class SidefpsController {
mFingerprintManager.setSidefpsController(mSidefpsControllerImpl);
}
- void show() {
+ private void show() {
mView = (SidefpsView) mInflater.inflate(R.layout.sidefps_view, null, false);
mView.setSensorProperties(mSensorProps);
mWindowManager.addView(mView, computeLayoutParams());
+ mOrientationListener.enable();
}
- void hide() {
+ private void hide() {
if (mView != null) {
mWindowManager.removeView(mView);
mView.setOnTouchListener(null);
@@ -135,13 +144,16 @@ public class SidefpsController {
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
}
+
+ mOrientationListener.disable();
}
- void onOrientationChanged() {
+ private void onOrientationChanged() {
// If mView is null or if view is hidden, then return.
if (mView == null || !mIsVisible) {
return;
}
+
// If the overlay needs to be displayed with a new configuration, destroy the current
// overlay, and re-create and show the overlay with the updated LayoutParams.
hide();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 710aca038569..f9103b56200b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -79,6 +79,8 @@ import java.util.Optional;
import javax.inject.Inject;
+import kotlin.Unit;
+
/**
* Shows and hides the under-display fingerprint sensor (UDFPS) overlay, handles UDFPS touch events,
* and coordinates triggering of the high-brightness mode (HBM).
@@ -118,6 +120,7 @@ public class UdfpsController implements DozeReceiver {
@NonNull private final AccessibilityManager mAccessibilityManager;
@NonNull private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@Nullable private final UdfpsHbmProvider mHbmProvider;
+ @VisibleForTesting @NonNull final BiometricOrientationEventListener mOrientationListener;
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
// sensors, this, in addition to a lot of the code here, will be updated.
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
@@ -511,6 +514,10 @@ public class UdfpsController implements DozeReceiver {
mHbmProvider = hbmProvider.orElse(null);
screenLifecycle.addObserver(mScreenObserver);
mScreenOn = screenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_ON;
+ mOrientationListener = new BiometricOrientationEventListener(context, () -> {
+ onOrientationChanged();
+ return Unit.INSTANCE;
+ });
mSensorProps = findFirstUdfps();
// At least one UDFPS sensor exists
@@ -650,7 +657,7 @@ public class UdfpsController implements DozeReceiver {
return mCoreLayoutParams;
}
- void onOrientationChanged() {
+ private void onOrientationChanged() {
// When the configuration changes it's almost always necessary to destroy and re-create
// the overlay's window to pass it the new LayoutParams.
// Hiding the overlay will destroy its window. It's safe to hide the overlay regardless
@@ -668,6 +675,7 @@ public class UdfpsController implements DozeReceiver {
if (mView == null) {
try {
Log.v(TAG, "showUdfpsOverlay | adding window reason=" + reason);
+
mView = (UdfpsView) mInflater.inflate(R.layout.udfps_view, null, false);
mOnFingerDown = false;
mView.setSensorProperties(mSensorProps);
@@ -675,6 +683,7 @@ public class UdfpsController implements DozeReceiver {
UdfpsAnimationViewController animation = inflateUdfpsAnimation(reason);
animation.init();
mView.setAnimationViewController(animation);
+ mOrientationListener.enable();
// This view overlaps the sensor area, so prevent it from being selectable
// during a11y.
@@ -768,6 +777,8 @@ public class UdfpsController implements DozeReceiver {
} else {
Log.v(TAG, "hideUdfpsOverlay | the overlay is already hidden");
}
+
+ mOrientationListener.disable();
}
/**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index bfcd1310acc2..e94f836337a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -20,7 +20,9 @@ import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -55,12 +57,13 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.os.Bundle;
import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableContext;
import android.testing.TestableLooper.RunWithLooper;
import android.view.WindowManager;
+import androidx.test.filters.SmallTest;
+
import com.android.internal.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.CommandQueue;
@@ -539,6 +542,17 @@ public class AuthControllerTest extends SysuiTestCase {
verify(mUdfpsController).onAodInterrupt(eq(pos), eq(pos), eq(majorMinor), eq(majorMinor));
}
+ @Test
+ public void testSubscribesToOrientationChangesWhenShowingDialog() {
+ assertFalse(mAuthController.mOrientationListener.getEnabled());
+
+ showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
+ assertTrue(mAuthController.mOrientationListener.getEnabled());
+
+ mAuthController.hideAuthenticationDialog();
+ assertFalse(mAuthController.mOrientationListener.getEnabled());
+ }
+
// Helpers
private void showDialog(int[] sensorIds, boolean credentialAllowed) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
new file mode 100644
index 000000000000..7019a4bbb08c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SidefpsControllerTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.biometrics
+
+import android.hardware.biometrics.SensorProperties
+import android.hardware.display.DisplayManagerGlobal
+import android.hardware.fingerprint.FingerprintManager
+import android.hardware.fingerprint.FingerprintSensorProperties
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
+import android.hardware.fingerprint.ISidefpsController
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.Display
+import android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS
+import android.view.DisplayInfo
+import android.view.LayoutInflater
+import android.view.WindowManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Mock
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+
+private const val DISPLAY_ID = 2
+private const val SENSOR_ID = 1
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class SidefpsControllerTest : SysuiTestCase() {
+
+ @JvmField @Rule
+ var rule = MockitoJUnit.rule()
+
+ @Mock
+ lateinit var layoutInflater: LayoutInflater
+ @Mock
+ lateinit var fingerprintManager: FingerprintManager
+ @Mock
+ lateinit var windowManager: WindowManager
+ @Mock
+ lateinit var sidefpsView: SidefpsView
+
+ private val executor = FakeExecutor(FakeSystemClock())
+ private lateinit var overlayController: ISidefpsController
+ private lateinit var sideFpsController: SidefpsController
+
+ @Before
+ fun setup() {
+ `when`(layoutInflater.inflate(R.layout.sidefps_view, null, false)).thenReturn(sidefpsView)
+ `when`(fingerprintManager.sensorPropertiesInternal).thenReturn(
+ listOf(
+ FingerprintSensorPropertiesInternal(
+ SENSOR_ID,
+ SensorProperties.STRENGTH_STRONG,
+ 5 /* maxEnrollmentsPerUser */,
+ listOf() /* componentInfo */,
+ FingerprintSensorProperties.TYPE_POWER_BUTTON,
+ true /* resetLockoutRequiresHardwareAuthToken */
+ )
+ )
+ )
+ `when`(windowManager.defaultDisplay).thenReturn(
+ Display(
+ DisplayManagerGlobal.getInstance(),
+ DISPLAY_ID,
+ DisplayInfo(),
+ DEFAULT_DISPLAY_ADJUSTMENTS
+ )
+ )
+
+ sideFpsController = SidefpsController(
+ mContext, layoutInflater, fingerprintManager, windowManager, executor
+ )
+
+ overlayController = ArgumentCaptor.forClass(ISidefpsController::class.java).apply {
+ verify(fingerprintManager).setSidefpsController(capture())
+ }.value
+ }
+
+ @Test
+ fun testSubscribesToOrientationChangesWhenShowingOverlay() {
+ assertThat(sideFpsController.mOrientationListener.enabled).isFalse()
+
+ overlayController.show()
+ executor.runAllReady()
+ assertThat(sideFpsController.mOrientationListener.enabled).isTrue()
+
+ overlayController.hide()
+ executor.runAllReady()
+ assertThat(sideFpsController.mOrientationListener.enabled).isFalse()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 25722e1c956b..d8d3676d4fa2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -17,6 +17,8 @@
package com.android.systemui.biometrics;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -236,6 +238,22 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
+ assertFalse(mUdfpsController.mOrientationListener.getEnabled());
+
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ assertTrue(mUdfpsController.mOrientationListener.getEnabled());
+
+ mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+ mFgExecutor.runAllReady();
+
+ assertFalse(mUdfpsController.mOrientationListener.getEnabled());
+ }
+
+ @Test
public void fingerDown() throws RemoteException {
// Configure UdfpsView to accept the ACTION_DOWN event
when(mUdfpsView.isIlluminationRequested()).thenReturn(false);