Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5cfbe141 authored by Austin Delgado's avatar Austin Delgado
Browse files

Add simFingerDown, simFingerUp, onUiReady to UdfpsShell

adb shell cmd statusbar udfps simFingerDown
  - Simulates onFingerDown within sensor in UdfpsController
adb shell cmd statusbar udfps simFingerUp
  - Simulates onFingerUp within sensor in UdfpsController
adb shell cmd statusbar udfps onUiReady
  - Runs onUiReady on AlternateTouchProvider

Bug: 250710937
Test: Manual testing
Change-Id: I1bec8aab5614c0b53e62324bd3fd608062b0badd
parent 7a5652f7
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -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;
@@ -285,6 +286,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);
            }
        }
    }

    /**
+69 −0
Original line number Diff line number Diff line
@@ -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
@@ -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
@@ -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.
@@ -68,6 +76,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)
        }
@@ -81,6 +95,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) {
@@ -126,4 +145,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)
    }
}
+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())
    }
}