Loading packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +25 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Point; import android.graphics.Rect; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.FingerprintManager; Loading Loading @@ -299,6 +300,30 @@ public class UdfpsController implements DozeReceiver { mOverlay.getOverlayView().setDebugMessage(message); }); } public Rect getSensorBounds() { return mOverlayParams.getSensorBounds(); } /** * Passes a mocked MotionEvent to OnTouch. * * @param event MotionEvent to simulate in onTouch */ public void debugOnTouch(long requestId, MotionEvent event) { UdfpsController.this.onTouch(requestId, event, false); } /** * Debug to run onUiReady */ public void debugOnUiReady(long requestId, int sensorId) { if (UdfpsController.this.mAlternateTouchProvider != null) { UdfpsController.this.mAlternateTouchProvider.onUiReady(); } else { UdfpsController.this.mFingerprintManager.onUiReady(requestId, sensorId); } } } /** Loading packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt +69 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.biometrics import android.content.Context import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER Loading @@ -27,6 +28,11 @@ import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN import android.hardware.fingerprint.IUdfpsOverlayControllerCallback import android.util.Log import android.view.LayoutInflater import android.view.MotionEvent import android.view.MotionEvent.ACTION_DOWN import android.view.MotionEvent.ACTION_MOVE import android.view.MotionEvent.ACTION_UP import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry Loading @@ -36,6 +42,8 @@ import javax.inject.Inject private const val TAG = "UdfpsShell" private const val REQUEST_ID = 2L private const val SENSOR_ID = 0 private const val MINOR = 10F private const val MAJOR = 10F /** * Used to show and hide the UDFPS overlay with statusbar commands. Loading Loading @@ -67,6 +75,12 @@ class UdfpsShell @Inject constructor( hideUdfpsOverlay() } else if (args.size == 2 && args[0] == "show") { showOverlay(getEnrollmentReason(args[1])) } else if (args.size == 1 && args[0] == "onUiReady") { onUiReady() } else if (args.size == 1 && args[0] == "simFingerDown") { simFingerDown() } else if (args.size == 1 && args[0] == "simFingerUp") { simFingerUp() } else { invalidCommand(pw) } Loading @@ -80,6 +94,11 @@ class UdfpsShell @Inject constructor( "auth-keyguard, auth-other, auth-settings]") pw.println(" -> reason otherwise defaults to unknown") pw.println(" - hide") pw.println(" - onUiReady") pw.println(" - simFingerDown") pw.println(" -> Simulates onFingerDown on sensor") pw.println(" - simFingerUp") pw.println(" -> Simulates onFingerUp on sensor") } private fun invalidCommand(pw: PrintWriter) { Loading Loading @@ -125,4 +144,54 @@ class UdfpsShell @Inject constructor( private fun hideOverlay() { udfpsOverlayController?.hideUdfpsOverlay(SENSOR_ID) } @VisibleForTesting fun onUiReady() { udfpsOverlayController?.debugOnUiReady(REQUEST_ID, SENSOR_ID) } @VisibleForTesting fun simFingerDown() { val sensorBounds: Rect = udfpsOverlayController!!.sensorBounds val downEvent: MotionEvent? = obtainMotionEvent(ACTION_DOWN, sensorBounds.exactCenterX(), sensorBounds.exactCenterY(), MINOR, MAJOR) udfpsOverlayController?.debugOnTouch(REQUEST_ID, downEvent) val moveEvent: MotionEvent? = obtainMotionEvent(ACTION_MOVE, sensorBounds.exactCenterX(), sensorBounds.exactCenterY(), MINOR, MAJOR) udfpsOverlayController?.debugOnTouch(REQUEST_ID, moveEvent) downEvent?.recycle() moveEvent?.recycle() } @VisibleForTesting fun simFingerUp() { val sensorBounds: Rect = udfpsOverlayController!!.sensorBounds val upEvent: MotionEvent? = obtainMotionEvent(ACTION_UP, sensorBounds.exactCenterX(), sensorBounds.exactCenterY(), MINOR, MAJOR) udfpsOverlayController?.debugOnTouch(REQUEST_ID, upEvent) upEvent?.recycle() } private fun obtainMotionEvent( action: Int, x: Float, y: Float, minor: Float, major: Float ): MotionEvent? { val pp = MotionEvent.PointerProperties() pp.id = 1 val pc = MotionEvent.PointerCoords() pc.x = x pc.y = y pc.touchMinor = minor pc.touchMajor = major return MotionEvent.obtain(0, 0, action, 1, arrayOf(pp), arrayOf(pc), 0, 0, 1f, 1f, 0, 0, 0, 0) } } packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * 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.graphics.Rect import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.MotionEvent import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.UdfpsController.UdfpsOverlayController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.util.mockito.any import junit.framework.Assert.assertEquals 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.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenEver import org.mockito.junit.MockitoJUnit @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class UdfpsShellTest : SysuiTestCase() { @JvmField @Rule var rule = MockitoJUnit.rule() // Unit under test private lateinit var udfpsShell: UdfpsShell @Mock lateinit var commandRegistry: CommandRegistry @Mock lateinit var udfpsOverlay: UdfpsOverlay @Mock lateinit var udfpsOverlayController: UdfpsOverlayController @Captor private lateinit var motionEvent: ArgumentCaptor<MotionEvent> private val sensorBounds = Rect() @Before fun setup() { whenEver(udfpsOverlayController.sensorBounds).thenReturn(sensorBounds) udfpsShell = UdfpsShell(commandRegistry, udfpsOverlay) udfpsShell.udfpsOverlayController = udfpsOverlayController } @Test fun testSimFingerDown() { udfpsShell.simFingerDown() verify(udfpsOverlayController, times(2)).debugOnTouch(any(), motionEvent.capture()) assertEquals(motionEvent.allValues[0].action, MotionEvent.ACTION_DOWN) // ACTION_MOVE assertEquals(motionEvent.allValues[1].action, MotionEvent.ACTION_MOVE) // ACTION_MOVE } @Test fun testSimFingerUp() { udfpsShell.simFingerUp() verify(udfpsOverlayController).debugOnTouch(any(), motionEvent.capture()) assertEquals(motionEvent.value.action, MotionEvent.ACTION_UP) } @Test fun testOnUiReady() { udfpsShell.onUiReady() verify(udfpsOverlayController).debugOnUiReady(any(), any()) } } Loading
packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +25 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Point; import android.graphics.Rect; import android.hardware.biometrics.BiometricFingerprintConstants; import android.hardware.display.DisplayManager; import android.hardware.fingerprint.FingerprintManager; Loading Loading @@ -299,6 +300,30 @@ public class UdfpsController implements DozeReceiver { mOverlay.getOverlayView().setDebugMessage(message); }); } public Rect getSensorBounds() { return mOverlayParams.getSensorBounds(); } /** * Passes a mocked MotionEvent to OnTouch. * * @param event MotionEvent to simulate in onTouch */ public void debugOnTouch(long requestId, MotionEvent event) { UdfpsController.this.onTouch(requestId, event, false); } /** * Debug to run onUiReady */ public void debugOnUiReady(long requestId, int sensorId) { if (UdfpsController.this.mAlternateTouchProvider != null) { UdfpsController.this.mAlternateTouchProvider.onUiReady(); } else { UdfpsController.this.mFingerprintManager.onUiReady(requestId, sensorId); } } } /** Loading
packages/SystemUI/src/com/android/systemui/biometrics/UdfpsShell.kt +69 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.biometrics import android.content.Context import android.graphics.Rect import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER Loading @@ -27,6 +28,11 @@ import android.hardware.biometrics.BiometricOverlayConstants.REASON_UNKNOWN import android.hardware.fingerprint.IUdfpsOverlayControllerCallback import android.util.Log import android.view.LayoutInflater import android.view.MotionEvent import android.view.MotionEvent.ACTION_DOWN import android.view.MotionEvent.ACTION_MOVE import android.view.MotionEvent.ACTION_UP import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.commandline.Command import com.android.systemui.statusbar.commandline.CommandRegistry Loading @@ -36,6 +42,8 @@ import javax.inject.Inject private const val TAG = "UdfpsShell" private const val REQUEST_ID = 2L private const val SENSOR_ID = 0 private const val MINOR = 10F private const val MAJOR = 10F /** * Used to show and hide the UDFPS overlay with statusbar commands. Loading Loading @@ -67,6 +75,12 @@ class UdfpsShell @Inject constructor( hideUdfpsOverlay() } else if (args.size == 2 && args[0] == "show") { showOverlay(getEnrollmentReason(args[1])) } else if (args.size == 1 && args[0] == "onUiReady") { onUiReady() } else if (args.size == 1 && args[0] == "simFingerDown") { simFingerDown() } else if (args.size == 1 && args[0] == "simFingerUp") { simFingerUp() } else { invalidCommand(pw) } Loading @@ -80,6 +94,11 @@ class UdfpsShell @Inject constructor( "auth-keyguard, auth-other, auth-settings]") pw.println(" -> reason otherwise defaults to unknown") pw.println(" - hide") pw.println(" - onUiReady") pw.println(" - simFingerDown") pw.println(" -> Simulates onFingerDown on sensor") pw.println(" - simFingerUp") pw.println(" -> Simulates onFingerUp on sensor") } private fun invalidCommand(pw: PrintWriter) { Loading Loading @@ -125,4 +144,54 @@ class UdfpsShell @Inject constructor( private fun hideOverlay() { udfpsOverlayController?.hideUdfpsOverlay(SENSOR_ID) } @VisibleForTesting fun onUiReady() { udfpsOverlayController?.debugOnUiReady(REQUEST_ID, SENSOR_ID) } @VisibleForTesting fun simFingerDown() { val sensorBounds: Rect = udfpsOverlayController!!.sensorBounds val downEvent: MotionEvent? = obtainMotionEvent(ACTION_DOWN, sensorBounds.exactCenterX(), sensorBounds.exactCenterY(), MINOR, MAJOR) udfpsOverlayController?.debugOnTouch(REQUEST_ID, downEvent) val moveEvent: MotionEvent? = obtainMotionEvent(ACTION_MOVE, sensorBounds.exactCenterX(), sensorBounds.exactCenterY(), MINOR, MAJOR) udfpsOverlayController?.debugOnTouch(REQUEST_ID, moveEvent) downEvent?.recycle() moveEvent?.recycle() } @VisibleForTesting fun simFingerUp() { val sensorBounds: Rect = udfpsOverlayController!!.sensorBounds val upEvent: MotionEvent? = obtainMotionEvent(ACTION_UP, sensorBounds.exactCenterX(), sensorBounds.exactCenterY(), MINOR, MAJOR) udfpsOverlayController?.debugOnTouch(REQUEST_ID, upEvent) upEvent?.recycle() } private fun obtainMotionEvent( action: Int, x: Float, y: Float, minor: Float, major: Float ): MotionEvent? { val pp = MotionEvent.PointerProperties() pp.id = 1 val pc = MotionEvent.PointerCoords() pc.x = x pc.y = y pc.touchMinor = minor pc.touchMajor = major return MotionEvent.obtain(0, 0, action, 1, arrayOf(pp), arrayOf(pc), 0, 0, 1f, 1f, 0, 0, 0, 0) } }
packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsShellTest.kt 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * 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.graphics.Rect import android.testing.AndroidTestingRunner import android.testing.TestableLooper import android.view.MotionEvent import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.UdfpsController.UdfpsOverlayController import com.android.systemui.statusbar.commandline.CommandRegistry import com.android.systemui.util.mockito.any import junit.framework.Assert.assertEquals 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.Mockito.times import org.mockito.Mockito.verify import org.mockito.Mockito.`when` as whenEver import org.mockito.junit.MockitoJUnit @SmallTest @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class UdfpsShellTest : SysuiTestCase() { @JvmField @Rule var rule = MockitoJUnit.rule() // Unit under test private lateinit var udfpsShell: UdfpsShell @Mock lateinit var commandRegistry: CommandRegistry @Mock lateinit var udfpsOverlay: UdfpsOverlay @Mock lateinit var udfpsOverlayController: UdfpsOverlayController @Captor private lateinit var motionEvent: ArgumentCaptor<MotionEvent> private val sensorBounds = Rect() @Before fun setup() { whenEver(udfpsOverlayController.sensorBounds).thenReturn(sensorBounds) udfpsShell = UdfpsShell(commandRegistry, udfpsOverlay) udfpsShell.udfpsOverlayController = udfpsOverlayController } @Test fun testSimFingerDown() { udfpsShell.simFingerDown() verify(udfpsOverlayController, times(2)).debugOnTouch(any(), motionEvent.capture()) assertEquals(motionEvent.allValues[0].action, MotionEvent.ACTION_DOWN) // ACTION_MOVE assertEquals(motionEvent.allValues[1].action, MotionEvent.ACTION_MOVE) // ACTION_MOVE } @Test fun testSimFingerUp() { udfpsShell.simFingerUp() verify(udfpsOverlayController).debugOnTouch(any(), motionEvent.capture()) assertEquals(motionEvent.value.action, MotionEvent.ACTION_UP) } @Test fun testOnUiReady() { udfpsShell.onUiReady() verify(udfpsOverlayController).debugOnUiReady(any(), any()) } }