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

Commit df01b10b authored by Ilya Matyukhin's avatar Ilya Matyukhin
Browse files

Log BiometricTouchReported atom

Metrics Design Review: eldar/679999406

Bug: 261101489
Test: atest UdfpsControllerTest
Test: m statsd_testdrive && statsd_testdrive 577
Change-Id: I23a8d4791d0e8f05787aac4f711406a966e6a2a7
parent fb7e58c5
Loading
Loading
Loading
Loading
+75 −1
Original line number Diff line number Diff line
@@ -16,8 +16,13 @@

package com.android.systemui.biometrics;

import static android.app.StatusBarManager.SESSION_BIOMETRIC_PROMPT;
import static android.app.StatusBarManager.SESSION_KEYGUARD;
import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP;
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD;
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING;
import static android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR;

import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.classifier.Classifier.LOCK_ICON;
@@ -37,6 +42,7 @@ import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.Process;
@@ -76,9 +82,11 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionStateManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.LockscreenShadeTransitionController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -121,6 +129,10 @@ public class UdfpsController implements DozeReceiver, Dumpable {

    // Minimum required delay between consecutive touch logs in milliseconds.
    private static final long MIN_TOUCH_LOG_INTERVAL = 50;
    private static final long MIN_UNCHANGED_INTERACTION_LOG_INTERVAL = 50;

    // This algorithm checks whether the touch is within the sensor's bounding box.
    private static final int BOUNDING_BOX_TOUCH_CONFIG_ID = 0;

    private final Context mContext;
    private final Execution mExecution;
@@ -151,6 +163,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
    @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
    @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
    @Nullable private final TouchProcessor mTouchProcessor;
    @NonNull private final SessionTracker mSessionTracker;
    @NonNull private final AlternateBouncerInteractor mAlternateBouncerInteractor;

    // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
@@ -168,6 +181,8 @@ public class UdfpsController implements DozeReceiver, Dumpable {
    private int mActivePointerId = -1;
    // The timestamp of the most recent touch log.
    private long mTouchLogTime;
    // The timestamp of the most recent log of the UNCHANGED interaction.
    private long mLastUnchangedInteractionTime;
    // Sensor has a capture (good or bad) for this touch. No need to enable the UDFPS display mode
    // anymore for this particular touch event. In other words, do not enable the UDFPS mode until
    // the user touches the sensor area again.
@@ -491,6 +506,63 @@ public class UdfpsController implements DozeReceiver, Dumpable {
        }
    }

    private int getBiometricSessionType() {
        if (mOverlay == null) {
            return -1;
        }
        switch (mOverlay.getRequestReason()) {
            case REASON_AUTH_KEYGUARD:
                return SESSION_KEYGUARD;
            case REASON_AUTH_BP:
                return SESSION_BIOMETRIC_PROMPT;
            case REASON_ENROLL_FIND_SENSOR:
            case REASON_ENROLL_ENROLLING:
                // TODO(b/255634916): create a reason for enrollment (or an "unknown" reason).
                return SESSION_BIOMETRIC_PROMPT << 1;
            default:
                return -1;
        }
    }

    private static int toBiometricTouchReportedTouchType(InteractionEvent event) {
        switch (event) {
            case DOWN:
                return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_DOWN;
            case UP:
                return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_UP;
            case CANCEL:
                return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_CANCEL;
            default:
                return SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED__TOUCH_TYPE__TOUCH_TYPE_UNCHANGED;
        }
    }

    private void logBiometricTouch(InteractionEvent event, NormalizedTouchData data) {
        if (event == InteractionEvent.UNCHANGED) {
            long sinceLastLog = mSystemClock.elapsedRealtime() - mLastUnchangedInteractionTime;
            if (sinceLastLog < MIN_UNCHANGED_INTERACTION_LOG_INTERVAL) {
                return;
            }
            mLastUnchangedInteractionTime = mSystemClock.elapsedRealtime();
        }

        final int biometricTouchReportedTouchType = toBiometricTouchReportedTouchType(event);
        final int sessionId = mSessionTracker.getSessionId(getBiometricSessionType()).getId();
        final int touchConfigId = BOUNDING_BOX_TOUCH_CONFIG_ID;

        SysUiStatsLog.write(SysUiStatsLog.BIOMETRIC_TOUCH_REPORTED, biometricTouchReportedTouchType,
                touchConfigId, sessionId, data.getX(), data.getY(), data.getMinor(),
                data.getMajor(), data.getOrientation(), data.getTime(), data.getGestureStart(),
                mStatusBarStateController.isDozing());

        if (Build.isDebuggable()) {
            Log.d(TAG, data.toPrettyString(event.toString()));
            Log.d(TAG, "sessionId: " + sessionId
                    + ", isAod: " + mStatusBarStateController.isDozing()
                    + ", touchConfigId: " + touchConfigId);
        }
    }

    private boolean newOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
        if (!fromUdfpsView) {
            Log.e(TAG, "ignoring the touch injected from outside of UdfpsView");
@@ -555,10 +627,10 @@ public class UdfpsController implements DozeReceiver, Dumpable {
                mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
                break;


            default:
                break;
        }
        logBiometricTouch(processedTouch.getEvent(), data);

        // We should only consume touches that are within the sensor. By returning "false" for
        // touches outside of the sensor, we let other UI components consume these events and act on
@@ -754,6 +826,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
            @NonNull @BiometricsBackground Executor biometricsExecutor,
            @NonNull PrimaryBouncerInteractor primaryBouncerInteractor,
            @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor,
            @NonNull SessionTracker sessionTracker,
            @NonNull AlternateBouncerInteractor alternateBouncerInteractor) {
        mContext = context;
        mExecution = execution;
@@ -798,6 +871,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {

        mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
                ? singlePointerTouchProcessor : null;
        mSessionTracker = sessionTracker;

        mDumpManager.registerDumpable(TAG, this);

+15 −0
Original line number Diff line number Diff line
@@ -62,4 +62,19 @@ data class NormalizedTouchData(
            nativeSensorBounds.top <= y &&
            nativeSensorBounds.bottom >= y
    }

    @JvmOverloads
    fun toPrettyString(tag: String = ""): String =
        """
        |NormalizedTouchData [$tag] {
        |     pointerId: $pointerId
        |             x: $x
        |             y: $y
        |         minor: $minor
        |         major: $major
        |   orientation: $orientation
        |          time: $time
        |  gestureStart: $gestureStart
        |}
        """.trimMargin()
}
+7 −1
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ import android.view.accessibility.AccessibilityManager;

import androidx.test.filters.SmallTest;

import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.util.LatencyTracker;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.R;
@@ -83,6 +84,7 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.domain.interactor.AlternateBouncerInteractor;
import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.ShadeExpansionStateManager;
@@ -204,6 +206,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
    @Mock
    private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
    @Mock
    private SessionTracker mSessionTracker;
    @Mock
    private AlternateBouncerInteractor mAlternateBouncerInteractor;

    // Capture listeners so that they can be used to send events
@@ -240,6 +244,8 @@ public class UdfpsControllerTest extends SysuiTestCase {
                .thenReturn(mFpmOtherView);
        when(mEnrollView.getContext()).thenReturn(mContext);
        when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
        when(mSessionTracker.getSessionId(anyInt())).thenReturn(
                (new InstanceIdSequence(1 << 20)).newInstanceId());

        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
@@ -295,7 +301,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
                mDisplayManager, mHandler, mConfigurationController, mSystemClock,
                mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker,
                mActivityLaunchAnimator, alternateTouchProvider, mBiometricExecutor,
                mPrimaryBouncerInteractor, mSinglePointerTouchProcessor,
                mPrimaryBouncerInteractor, mSinglePointerTouchProcessor, mSessionTracker,
                mAlternateBouncerInteractor);
        verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
        mOverlayController = mOverlayCaptor.getValue();