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

Commit df06b6e5 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Support logging biometrics onboarding metrics" into main

parents 1651dfeb 7ed25b9b
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@ import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.Utils;
import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils;
import com.android.settings.biometrics.metrics.BiometricsLogger;
import com.android.settings.biometrics.metrics.OnboardingEvent;
import com.android.settings.core.InstrumentedActivity;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockGeneric;
@@ -65,6 +67,7 @@ import com.android.settings.password.ConfirmDeviceCredentialActivity;
import com.google.android.setupcompat.util.WizardManagerHelper;
import com.google.android.setupdesign.transition.TransitionHelper;

import java.util.ArrayList;
import java.util.List;

/**
@@ -139,6 +142,8 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
    @Nullable private ParentalConsentHelper mParentalConsentHelper;
    private boolean mIsPreviousEnrollmentCanceled = false;

    private List<OnboardingEvent> mOnboardingEvents = new ArrayList<>();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
@@ -527,6 +532,7 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
        Log.d(TAG, "handleOnActivityResultWhileEnrolling, request = " + requestCode + ""
                + ", resultCode = " + resultCode + ", launchFaceEnrollFirst="
                + mLaunchFaceEnrollFirst);
        updateOnboardingEventList(data);
        switch (requestCode) {
            case REQUEST_HANDOFF_PARENT:
                setResult(RESULT_OK, newResultIntent());
@@ -648,6 +654,14 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
        if (mPassThroughExtrasFromChosenLockInSuw != null) {
            intent.putExtras(mPassThroughExtrasFromChosenLockInSuw);
        }
        final BiometricsLogger logger = FeatureFactory.getFeatureFactory()
                .getBiometricsFeatureProvider().getBiometricsLogger();
        if (logger != null && !mOnboardingEvents.isEmpty()) {
            intent.putExtra(
                    BiometricsLogger.EXTRA_BIOMETRICS_ONBOARDING_EVENT_BYTES_LIST,
                    logger.eventListToRepeatedMessageByteArray(mOnboardingEvents)
            );
        }
        return intent;
    }

@@ -766,6 +780,12 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
            } else {
                intent = BiometricUtils.getFingerprintIntroIntent(this, getIntent());
            }
            if (getIntent().getBooleanExtra(
                    CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, false)) {
                intent.putExtra(
                        CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE,
                        true);
            }
            launchSingleSensorEnrollActivity(intent, REQUEST_SINGLE_ENROLL_FINGERPRINT);
        }
    }
@@ -774,6 +794,12 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
        if (!mIsSingleEnrolling) {
            mIsSingleEnrolling = true;
            final Intent intent = BiometricUtils.getFaceIntroIntent(this, getIntent());
            if (getIntent().getBooleanExtra(
                    CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, false)) {
                intent.putExtra(
                        CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE,
                        true);
            }
            launchSingleSensorEnrollActivity(intent, REQUEST_SINGLE_ENROLL_FACE);
        }
    }
@@ -796,4 +822,15 @@ public class BiometricEnrollActivity extends InstrumentedActivity {
    public int getMetricsCategory() {
        return SettingsEnums.BIOMETRIC_ENROLL_ACTIVITY;
    }

    private void updateOnboardingEventList(Intent data) {
        if (data != null && data.hasExtra(BiometricsLogger.EXTRA_BIOMETRICS_ONBOARDING_EVENT)) {
            final OnboardingEvent event = data.getParcelableExtra(
                    BiometricsLogger.EXTRA_BIOMETRICS_ONBOARDING_EVENT, OnboardingEvent.class);
            mOnboardingEvents.add(event);
            if (BiometricsLogger.LOGGABLE) {
                Log.d(BiometricsLogger.TAG, getClass().getSimpleName() + ": add Event:" + event);
            }
        }
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.safetycenter.SafetySourceIssue;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.settings.biometrics.metrics.BiometricsLogger;

public interface BiometricsFeatureProvider {

    /** Returns a SafetySourceIssue for biometrics. */
@@ -29,4 +31,8 @@ public interface BiometricsFeatureProvider {

    /** Notifies that the action of an issue is launched */
    void notifySafetyIssueActionLaunched();

    /** Return logger for biometrics */
    @Nullable
    BiometricsLogger getBiometricsLogger();
}
+8 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.safetycenter.SafetySourceIssue;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.settings.biometrics.metrics.BiometricsLogger;

public class BiometricsFeatureProviderImpl implements BiometricsFeatureProvider {
    @Nullable
    @Override
@@ -30,4 +32,10 @@ public class BiometricsFeatureProviderImpl implements BiometricsFeatureProvider

    @Override
    public void notifySafetyIssueActionLaunched() {}

    @Nullable
    @Override
    public BiometricsLogger getBiometricsLogger() {
        return null;
    }
}
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.settings.biometrics.metrics;

import android.annotation.Nullable;
import android.os.Build;

import androidx.annotation.NonNull;

import java.util.List;

/**
 * Logger class for biometrics
 */
public interface BiometricsLogger {
    String TAG = "BiometricsLogger";
    Boolean LOGGABLE = Build.isDebuggable();

    /** The bundle extra key for BiometricsOnboardingEvent used in Face/Fingerprint Enroll */
    String EXTRA_BIOMETRICS_ONBOARDING_EVENT = "biometrics_onboarding_event";

    /**
     * The bundle extra key for BiometricsOnboardingEvent in bytes array used in Face Enroll.
     */
    String EXTRA_BIOMETRICS_ONBOARDING_EVENT_BYTES = "biometrics_onboarding_event_bytes";

    /**
     * The bundle extra key for a list of BiometricsOnboardingEvent in byte array used in
     * Face /Fingerprint Enroll
     */
    String EXTRA_BIOMETRICS_ONBOARDING_EVENT_BYTES_LIST = "biometrics_onboarding_event_bytes_list";

    /** Log SettingsBiometricsOnboarding metrics */
    void logSettingsBiometricsOnboarding(@NonNull OnboardingEvent event);

    /** Convert BiometricOnboardingEvent to proto message byte array */
    byte[] eventToMessageByteArray(@NonNull OnboardingEvent event);

    /**
     * Convert proto message byte array to BiometricsOnboardingEvent.
     */
    @Nullable
    OnboardingEvent messageByteArrayToEvent(byte[] message);

    /**
     * Convert list of BiometricOnboardingEvent to repeated message byte array.
     */
    byte[] eventListToRepeatedMessageByteArray(@NonNull List<OnboardingEvent> events);
}
+210 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.settings.biometrics.metrics;

import android.os.Parcel;
import android.os.Parcelable;

import androidx.annotation.NonNull;

import com.android.settings.biometrics.BiometricsOnboardingProto;
import com.android.settings.biometrics.BiometricsOnboardingProto.OnboardingScreenInfo;
import com.android.settings.biometrics.BiometricsOnboardingProto.SettingsBiometricsOnboarding;

import java.util.ArrayList;
import java.util.List;

/**
 * Represents SettingsBiometricsOnboarding proto message.
 * See Settings/proto/biometrics_onboarding.proto.
 */
public class OnboardingEvent implements Parcelable {
    private int mModality;
    private int mFromSource;
    private int mUserId;
    private int mEnrolledCount;
    private long mDuration;
    private int mCapybaraStatus;
    private int mResultCode;
    private int mErrorCode;
    private List<OnboardingScreenInfoEvent> mScreenInfos = new ArrayList<>();

    public OnboardingEvent() {
    }

    public OnboardingEvent(SettingsBiometricsOnboarding message) {
        mModality = message.getModality().getNumber();
        mFromSource = message.getFromSource().getNumber();
        mUserId = message.getUser();
        mEnrolledCount = message.getEnrolledCount();
        mDuration = message.getDurationMillis();
        mCapybaraStatus = message.getCapybaraStatus();
        mResultCode = message.getResultCode().getNumber();
        mErrorCode = message.getErrorCode();
        final List<OnboardingScreenInfo> infoList =
                message.getOnboardingScreenInfoList().getInfoListList();
        for (OnboardingScreenInfo info : infoList) {
            mScreenInfos.add(new OnboardingScreenInfoEvent(
                    info.getOnboardingScreen().getNumber(),
                    info.getDwellTimeMillis(),
                    info.getOnboardingActionsList().stream().mapToInt(
                            BiometricsOnboardingProto.OnboardingAction::getNumber).toArray()
            ));
        }
    }

    protected OnboardingEvent(Parcel in) {
        mModality = in.readInt();
        mFromSource = in.readInt();
        mUserId = in.readInt();
        mEnrolledCount = in.readInt();
        mDuration = in.readLong();
        mCapybaraStatus = in.readInt();
        mResultCode = in.readInt();
        mErrorCode = in.readInt();
        in.readTypedList(mScreenInfos, OnboardingScreenInfoEvent.CREATOR);
    }

    public int getModality() {
        return mModality;
    }

    public void setModality(int modality) {
        mModality = modality;
    }

    public int getFromSource() {
        return mFromSource;
    }

    public void setFromSource(int fromSource) {
        mFromSource = fromSource;
    }

    public int getUserId() {
        return mUserId;
    }

    public void setUserId(int userId) {
        mUserId = userId;
    }

    public int getEnrolledCount() {
        return mEnrolledCount;
    }

    public void setEnrolledCount(int enrolledCount) {
        mEnrolledCount = enrolledCount;
    }

    public long getDuration() {
        return mDuration;
    }

    public void setDuration(long duration) {
        mDuration = duration;
    }

    public int getCapybaraStatus() {
        return mCapybaraStatus;
    }

    public void setCapybaraStatus(int capybaraStatus) {
        mCapybaraStatus = capybaraStatus;
    }

    public int getResultCode() {
        return mResultCode;
    }

    public void setResultCode(int resultCode) {
        mResultCode = resultCode;
    }

    public int getErrorCode() {
        return mErrorCode;
    }

    public void setErrorCode(int errorCode) {
        mErrorCode = errorCode;
    }

    @NonNull
    public List<OnboardingScreenInfoEvent> getScreenInfos() {
        return mScreenInfos;
    }

    /** Add screen info */
    public void addScreenInfo(@NonNull OnboardingScreenInfoEvent screenInfo) {
        mScreenInfos.add(screenInfo);
    }

    public static final Creator<OnboardingEvent> CREATOR = new Creator<>() {
        @Override
        public OnboardingEvent createFromParcel(Parcel in) {
            return new OnboardingEvent(in);
        }

        @Override
        public OnboardingEvent[] newArray(int size) {
            return new OnboardingEvent[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mModality);
        dest.writeInt(mFromSource);
        dest.writeInt(mUserId);
        dest.writeInt(mEnrolledCount);
        dest.writeLong(mDuration);
        dest.writeInt(mCapybaraStatus);
        dest.writeInt(mResultCode);
        dest.writeInt(mErrorCode);
        dest.writeTypedList(mScreenInfos);
    }

    @Override
    public String toString() {
        return "BiometricsOnboardingEvent{"
                + "mModality=" + mModality
                + ", mSource=" + mFromSource
                + ", mUserId=" + mUserId
                + ", mEnrolledCount=" + mEnrolledCount
                + ", mTotalTime=" + mDuration
                + ", mCapybaraStatus=" + mCapybaraStatus
                + ", mResultCode=" + mResultCode
                + ", mErrorCode=" + mErrorCode
                + ", mScreenInfos=" + screenInfosToString()
                + "}";
    }

    private String screenInfosToString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("{");
        for (OnboardingScreenInfoEvent screenInfo : mScreenInfos) {
            sb.append(screenInfo.toString());
            sb.append(", ");
        }
        return sb.append("}").toString();
    }
}
Loading