Merge "Log power & face auth wake reasons." into udc-dev
diff --git a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
index 82444f0..6bd4880 100644
--- a/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
+++ b/services/core/java/com/android/server/biometrics/log/BiometricFrameworkStatsLogger.java
@@ -16,14 +16,22 @@
 
 package com.android.server.biometrics.log;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.biometrics.BiometricsProtoEnums;
 import android.hardware.biometrics.IBiometricContextListener;
+import android.hardware.biometrics.common.AuthenticateReason;
+import android.hardware.biometrics.common.OperationContext;
 import android.hardware.biometrics.common.OperationReason;
+import android.hardware.biometrics.common.WakeReason;
 import android.util.Slog;
 import android.view.Surface;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FrameworkStatsLog;
 
+import java.util.stream.Stream;
+
 /**
  * Wrapper for {@link FrameworkStatsLog} to isolate the testable parts.
  */
@@ -63,7 +71,7 @@
                 orientationType(operationContext.getOrientation()),
                 foldType(operationContext.getFoldState()),
                 operationContext.getOrderAndIncrement(),
-                BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
+                toProtoWakeReason(operationContext));
     }
 
     /** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */
@@ -89,7 +97,8 @@
                 orientationType(operationContext.getOrientation()),
                 foldType(operationContext.getFoldState()),
                 operationContext.getOrderAndIncrement(),
-                BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
+                toProtoWakeReason(operationContext),
+                toProtoWakeReasonDetails(operationContext));
     }
 
     /** {@see FrameworkStatsLog.BIOMETRIC_AUTHENTICATED}. */
@@ -137,7 +146,81 @@
                 orientationType(operationContext.getOrientation()),
                 foldType(operationContext.getFoldState()),
                 operationContext.getOrderAndIncrement(),
-                BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
+                toProtoWakeReason(operationContext),
+                toProtoWakeReasonDetails(operationContext));
+    }
+
+    @VisibleForTesting
+    static int[] toProtoWakeReasonDetails(@NonNull OperationContextExt operationContext) {
+        final OperationContext ctx = operationContext.toAidlContext();
+        return Stream.of(toProtoWakeReasonDetails(ctx.authenticateReason))
+                .mapToInt(i -> i)
+                .filter(i -> i != BiometricsProtoEnums.DETAILS_UNKNOWN)
+                .toArray();
+    }
+
+    @VisibleForTesting
+    static int toProtoWakeReason(@NonNull OperationContextExt operationContext) {
+        @WakeReason final int reason = operationContext.getWakeReason();
+        switch (reason) {
+            case WakeReason.POWER_BUTTON:
+                return BiometricsProtoEnums.WAKE_REASON_POWER_BUTTON;
+            case WakeReason.GESTURE:
+                return BiometricsProtoEnums.WAKE_REASON_GESTURE;
+            case WakeReason.WAKE_KEY:
+                return BiometricsProtoEnums.WAKE_REASON_WAKE_KEY;
+            case WakeReason.WAKE_MOTION:
+                return BiometricsProtoEnums.WAKE_REASON_WAKE_MOTION;
+            case WakeReason.LID:
+                return BiometricsProtoEnums.WAKE_REASON_LID;
+            case WakeReason.DISPLAY_GROUP_ADDED:
+                return BiometricsProtoEnums.WAKE_REASON_DISPLAY_GROUP_ADDED;
+            case WakeReason.TAP:
+                return BiometricsProtoEnums.WAKE_REASON_TAP;
+            case WakeReason.LIFT:
+                return BiometricsProtoEnums.WAKE_REASON_LIFT;
+            case WakeReason.BIOMETRIC:
+                return BiometricsProtoEnums.WAKE_REASON_BIOMETRIC;
+            default:
+                return BiometricsProtoEnums.WAKE_REASON_UNKNOWN;
+        }
+    }
+
+    private static int toProtoWakeReasonDetails(@Nullable AuthenticateReason reason) {
+        if (reason != null) {
+            switch (reason.getTag()) {
+                case AuthenticateReason.faceAuthenticateReason:
+                    return toProtoWakeReasonDetailsFromFace(reason.getFaceAuthenticateReason());
+            }
+        }
+        return BiometricsProtoEnums.DETAILS_UNKNOWN;
+    }
+
+    private static int toProtoWakeReasonDetailsFromFace(@AuthenticateReason.Face int reason) {
+        switch (reason) {
+            case AuthenticateReason.Face.STARTED_WAKING_UP:
+                return BiometricsProtoEnums.DETAILS_FACE_STARTED_WAKING_UP;
+            case AuthenticateReason.Face.PRIMARY_BOUNCER_SHOWN:
+                return BiometricsProtoEnums.DETAILS_FACE_PRIMARY_BOUNCER_SHOWN;
+            case AuthenticateReason.Face.ASSISTANT_VISIBLE:
+                return BiometricsProtoEnums.DETAILS_FACE_ASSISTANT_VISIBLE;
+            case AuthenticateReason.Face.ALTERNATE_BIOMETRIC_BOUNCER_SHOWN:
+                return BiometricsProtoEnums.DETAILS_FACE_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN;
+            case AuthenticateReason.Face.NOTIFICATION_PANEL_CLICKED:
+                return BiometricsProtoEnums.DETAILS_FACE_NOTIFICATION_PANEL_CLICKED;
+            case AuthenticateReason.Face.OCCLUDING_APP_REQUESTED:
+                return BiometricsProtoEnums.DETAILS_FACE_OCCLUDING_APP_REQUESTED;
+            case AuthenticateReason.Face.PICK_UP_GESTURE_TRIGGERED:
+                return BiometricsProtoEnums.DETAILS_FACE_PICK_UP_GESTURE_TRIGGERED;
+            case AuthenticateReason.Face.QS_EXPANDED:
+                return BiometricsProtoEnums.DETAILS_FACE_QS_EXPANDED;
+            case AuthenticateReason.Face.SWIPE_UP_ON_BOUNCER:
+                return BiometricsProtoEnums.DETAILS_FACE_SWIPE_UP_ON_BOUNCER;
+            case AuthenticateReason.Face.UDFPS_POINTER_DOWN:
+                return BiometricsProtoEnums.DETAILS_FACE_UDFPS_POINTER_DOWN;
+            default:
+                return BiometricsProtoEnums.DETAILS_UNKNOWN;
+        }
     }
 
     /** {@see FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED}. */
diff --git a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
index ecb7e7c..2934339 100644
--- a/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
+++ b/services/core/java/com/android/server/biometrics/log/OperationContextExt.java
@@ -188,10 +188,17 @@
     }
 
     /** {@link OperationContext#reason}. */
+    @OperationReason
     public byte getReason() {
         return mAidlContext.reason;
     }
 
+    /** {@link OperationContext#wakeReason}. */
+    @WakeReason
+    public int getWakeReason() {
+        return mAidlContext.wakeReason;
+    }
+
     /** If the screen is currently on. */
     public boolean isDisplayOn() {
         return mIsDisplayOn;
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricFrameworkStatsLoggerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricFrameworkStatsLoggerTest.java
new file mode 100644
index 0000000..5adf391
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/log/BiometricFrameworkStatsLoggerTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 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.server.biometrics.log;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.common.AuthenticateReason;
+import android.hardware.biometrics.common.OperationContext;
+import android.hardware.biometrics.common.WakeReason;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@Presubmit
+@SmallTest
+public class BiometricFrameworkStatsLoggerTest {
+
+    @Test
+    public void testConvertsWakeReason_whenEmpty() {
+        final OperationContextExt ctx = new OperationContextExt();
+
+        final int reason = BiometricFrameworkStatsLogger.toProtoWakeReason(ctx);
+        final int[] reasonDetails = BiometricFrameworkStatsLogger
+                .toProtoWakeReasonDetails(ctx);
+
+        assertThat(reason).isEqualTo(BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
+        assertThat(reasonDetails).isEmpty();
+    }
+
+    @Test
+    public void testConvertsWakeReason_whenPowerReason() {
+        final OperationContext context = new OperationContext();
+        context.wakeReason = WakeReason.WAKE_MOTION;
+        final OperationContextExt ctx = new OperationContextExt(context);
+
+        final int reason = BiometricFrameworkStatsLogger.toProtoWakeReason(ctx);
+        final int[] reasonDetails = BiometricFrameworkStatsLogger
+                .toProtoWakeReasonDetails(new OperationContextExt(context));
+
+        assertThat(reason).isEqualTo(BiometricsProtoEnums.WAKE_REASON_WAKE_MOTION);
+        assertThat(reasonDetails).isEmpty();
+    }
+
+    @Test
+    public void testConvertsWakeReason_whenFaceReason() {
+        final OperationContext context = new OperationContext();
+        context.authenticateReason = AuthenticateReason.faceAuthenticateReason(
+                AuthenticateReason.Face.ASSISTANT_VISIBLE);
+        final OperationContextExt ctx = new OperationContextExt(context);
+
+        final int reason = BiometricFrameworkStatsLogger.toProtoWakeReason(ctx);
+        final int[] reasonDetails = BiometricFrameworkStatsLogger
+                .toProtoWakeReasonDetails(ctx);
+
+        assertThat(reason).isEqualTo(BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
+        assertThat(reasonDetails).asList().containsExactly(
+                BiometricsProtoEnums.DETAILS_FACE_ASSISTANT_VISIBLE);
+    }
+
+    @Test
+    public void testConvertsWakeReason_whenVendorReason() {
+        final OperationContext context = new OperationContext();
+        context.authenticateReason = AuthenticateReason.vendorAuthenticateReason(
+                new AuthenticateReason.Vendor());
+        final OperationContextExt ctx = new OperationContextExt(context);
+
+        final int reason = BiometricFrameworkStatsLogger.toProtoWakeReason(ctx);
+        final int[] reasonDetails = BiometricFrameworkStatsLogger
+                .toProtoWakeReasonDetails(ctx);
+
+        assertThat(reason).isEqualTo(BiometricsProtoEnums.WAKE_REASON_UNKNOWN);
+        assertThat(reasonDetails).isEmpty();
+    }
+
+
+    @Test
+    public void testConvertsWakeReason_whenPowerAndFaceReason() {
+        final OperationContext context = new OperationContext();
+        context.wakeReason = WakeReason.WAKE_KEY;
+        context.authenticateReason = AuthenticateReason.faceAuthenticateReason(
+                AuthenticateReason.Face.PRIMARY_BOUNCER_SHOWN);
+        final OperationContextExt ctx = new OperationContextExt(context);
+
+        final int reason = BiometricFrameworkStatsLogger.toProtoWakeReason(ctx);
+        final int[] reasonDetails = BiometricFrameworkStatsLogger
+                .toProtoWakeReasonDetails(ctx);
+
+        assertThat(reason).isEqualTo(BiometricsProtoEnums.WAKE_REASON_WAKE_KEY);
+        assertThat(reasonDetails).asList().containsExactly(
+                BiometricsProtoEnums.DETAILS_FACE_PRIMARY_BOUNCER_SHOWN);
+    }
+
+    @Test
+    public void testConvertsWakeReason_whenPowerAndVendorReason() {
+        final OperationContext context = new OperationContext();
+        context.wakeReason = WakeReason.LID;
+        context.authenticateReason = AuthenticateReason.vendorAuthenticateReason(
+                new AuthenticateReason.Vendor());
+        final OperationContextExt ctx = new OperationContextExt(context);
+
+        final int reason = BiometricFrameworkStatsLogger.toProtoWakeReason(ctx);
+        final int[] reasonDetails = BiometricFrameworkStatsLogger
+                .toProtoWakeReasonDetails(ctx);
+
+        assertThat(reason).isEqualTo(BiometricsProtoEnums.WAKE_REASON_LID);
+        assertThat(reasonDetails).isEmpty();
+    }
+}