| /* |
| * Copyright (C) 2022 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.autofill; |
| |
| import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG; |
| import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE; |
| import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU; |
| import static android.service.autofill.FillEventHistory.Event.UiType; |
| import static android.view.autofill.AutofillManager.COMMIT_REASON_ACTIVITY_FINISHED; |
| import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CHANGED; |
| import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CLICKED; |
| import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_COMMITTED; |
| |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC; |
| import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN; |
| import static com.android.server.autofill.Helper.sVerbose; |
| |
| import android.annotation.IntDef; |
| import android.annotation.Nullable; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.pm.PackageManager; |
| import android.provider.Settings; |
| import android.service.autofill.Dataset; |
| import android.text.TextUtils; |
| import android.util.Slog; |
| import android.view.autofill.AutofillId; |
| import android.view.autofill.AutofillManager; |
| |
| import com.android.internal.util.FrameworkStatsLog; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.List; |
| import java.util.Optional; |
| |
| /** Helper class to track and log Autofill presentation stats. */ |
| public final class PresentationStatsEventLogger { |
| private static final String TAG = "PresentationStatsEventLogger"; |
| |
| /** |
| * Reasons why presentation was not shown. These are wrappers around |
| * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}. |
| */ |
| @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = { |
| NOT_SHOWN_REASON_ANY_SHOWN, |
| NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED, |
| NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE, |
| NOT_SHOWN_REASON_VIEW_CHANGED, |
| NOT_SHOWN_REASON_ACTIVITY_FINISHED, |
| NOT_SHOWN_REASON_REQUEST_TIMEOUT, |
| NOT_SHOWN_REASON_REQUEST_FAILED, |
| NOT_SHOWN_REASON_NO_FOCUS, |
| NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY, |
| NOT_SHOWN_REASON_UNKNOWN |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface NotShownReason {} |
| |
| /** |
| * Reasons why presentation was not shown. These are wrappers around |
| * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationType}. |
| */ |
| @IntDef(prefix = {"AUTHENTICATION_TYPE"}, value = { |
| AUTHENTICATION_TYPE_UNKNOWN, |
| AUTHENTICATION_TYPE_DATASET_AUTHENTICATION, |
| AUTHENTICATION_TYPE_FULL_AUTHENTICATION |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface AuthenticationType { |
| } |
| |
| /** |
| * Reasons why presentation was not shown. These are wrappers around |
| * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationResult}. |
| */ |
| @IntDef(prefix = {"AUTHENTICATION_RESULT"}, value = { |
| AUTHENTICATION_RESULT_UNKNOWN, |
| AUTHENTICATION_RESULT_SUCCESS, |
| AUTHENTICATION_RESULT_FAILURE |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface AuthenticationResult { |
| } |
| |
| /** |
| * Reasons why the picked dataset was present. These are wrappers around |
| * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DatasetPickedReason}. |
| * This enum is similar to {@link android.service.autofill.Dataset.DatasetEligibleReason} |
| */ |
| @IntDef(prefix = {"PICK_REASON"}, value = { |
| PICK_REASON_UNKNOWN, |
| PICK_REASON_NO_PCC, |
| PICK_REASON_PROVIDER_DETECTION_ONLY, |
| PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC, |
| PICK_REASON_PCC_DETECTION_ONLY, |
| PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER, |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface DatasetPickedReason {} |
| |
| /** |
| * The type of detection that was preferred. These are wrappers around |
| * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DetectionPreference}. |
| */ |
| @IntDef(prefix = {"DETECTION_PREFER"}, value = { |
| DETECTION_PREFER_UNKNOWN, |
| DETECTION_PREFER_AUTOFILL_PROVIDER, |
| DETECTION_PREFER_PCC |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface DetectionPreference { |
| } |
| |
| public static final int NOT_SHOWN_REASON_ANY_SHOWN = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN; |
| public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED; |
| public static final int NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE; |
| public static final int NOT_SHOWN_REASON_VIEW_CHANGED = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED; |
| public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED; |
| public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT; |
| public static final int NOT_SHOWN_REASON_REQUEST_FAILED = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED; |
| public static final int NOT_SHOWN_REASON_NO_FOCUS = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS; |
| public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY; |
| public static final int NOT_SHOWN_REASON_UNKNOWN = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON; |
| |
| public static final int AUTHENTICATION_TYPE_UNKNOWN = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN; |
| public static final int AUTHENTICATION_TYPE_DATASET_AUTHENTICATION = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION; |
| public static final int AUTHENTICATION_TYPE_FULL_AUTHENTICATION = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION; |
| |
| public static final int AUTHENTICATION_RESULT_UNKNOWN = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN; |
| public static final int AUTHENTICATION_RESULT_SUCCESS = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS; |
| public static final int AUTHENTICATION_RESULT_FAILURE = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE; |
| |
| public static final int PICK_REASON_UNKNOWN = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN; |
| public static final int PICK_REASON_NO_PCC = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC; |
| public static final int PICK_REASON_PROVIDER_DETECTION_ONLY = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY; |
| public static final int PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC; |
| public static final int PICK_REASON_PCC_DETECTION_ONLY = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY; |
| public static final int PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER; |
| |
| |
| // Values for AutofillFillResponseReported.detection_preference |
| public static final int DETECTION_PREFER_UNKNOWN = |
| AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN; |
| public static final int DETECTION_PREFER_AUTOFILL_PROVIDER = |
| AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER; |
| public static final int DETECTION_PREFER_PCC = |
| AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC; |
| private final int mSessionId; |
| |
| /** |
| * For app_package_uid. |
| */ |
| private final int mCallingAppUid; |
| private Optional<PresentationStatsEventInternal> mEventInternal; |
| |
| private PresentationStatsEventLogger(int sessionId, int callingAppUid) { |
| mSessionId = sessionId; |
| mCallingAppUid = callingAppUid; |
| mEventInternal = Optional.empty(); |
| } |
| |
| /** |
| * Create PresentationStatsEventLogger, populated with sessionId and the callingAppUid |
| */ |
| public static PresentationStatsEventLogger createPresentationLog( |
| int sessionId, int callingAppUid) { |
| return new PresentationStatsEventLogger(sessionId, callingAppUid); |
| } |
| |
| public void startNewEvent() { |
| if (mEventInternal.isPresent()) { |
| Slog.e(TAG, "Failed to start new event because already have active event."); |
| return; |
| } |
| mEventInternal = Optional.of(new PresentationStatsEventInternal()); |
| } |
| |
| public void maybeSetRequestId(int requestId) { |
| mEventInternal.ifPresent(event -> event.mRequestId = requestId); |
| } |
| |
| public void maybeSetNoPresentationEventReason(@NotShownReason int reason) { |
| mEventInternal.ifPresent(event -> { |
| if (event.mCountShown == 0) { |
| event.mNoPresentationReason = reason; |
| } |
| }); |
| } |
| |
| public void maybeSetNoPresentationEventReasonIfNoReasonExists(@NotShownReason int reason) { |
| mEventInternal.ifPresent(event -> { |
| if (event.mCountShown == 0 && event.mNoPresentationReason == NOT_SHOWN_REASON_UNKNOWN) { |
| event.mNoPresentationReason = reason; |
| } |
| }); |
| } |
| |
| public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList, |
| AutofillId currentViewId) { |
| mEventInternal.ifPresent(event -> { |
| CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId); |
| event.mAvailableCount = container.mAvailableCount; |
| event.mAvailablePccCount = container.mAvailablePccCount; |
| event.mAvailablePccOnlyCount = container.mAvailablePccOnlyCount; |
| event.mIsDatasetAvailable = container.mAvailableCount > 0; |
| }); |
| } |
| |
| public void maybeSetCountShown(@Nullable List<Dataset> datasetList, |
| AutofillId currentViewId) { |
| mEventInternal.ifPresent(event -> { |
| CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId); |
| event.mCountShown = container.mAvailableCount; |
| if (container.mAvailableCount > 0) { |
| event.mNoPresentationReason = NOT_SHOWN_REASON_ANY_SHOWN; |
| } |
| }); |
| } |
| |
| private static CountContainer getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList, |
| AutofillId currentViewId) { |
| |
| CountContainer container = new CountContainer(); |
| if (datasetList != null) { |
| for (int i = 0; i < datasetList.size(); i++) { |
| Dataset data = datasetList.get(i); |
| if (data != null && data.getFieldIds() != null |
| && data.getFieldIds().contains(currentViewId)) { |
| container.mAvailableCount += 1; |
| if (data.getEligibleReason() == PICK_REASON_PCC_DETECTION_ONLY) { |
| container.mAvailablePccOnlyCount++; |
| container.mAvailablePccCount++; |
| } else if (data.getEligibleReason() |
| == PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER) { |
| container.mAvailablePccCount++; |
| } |
| } |
| } |
| } |
| return container; |
| } |
| |
| private static class CountContainer{ |
| int mAvailableCount = 0; |
| int mAvailablePccCount = 0; |
| int mAvailablePccOnlyCount = 0; |
| |
| CountContainer() {} |
| |
| CountContainer(int availableCount, int availablePccCount, |
| int availablePccOnlyCount) { |
| mAvailableCount = availableCount; |
| mAvailablePccCount = availablePccCount; |
| mAvailablePccOnlyCount = availablePccOnlyCount; |
| } |
| } |
| |
| public void maybeSetCountFilteredUserTyping(int countFilteredUserTyping) { |
| mEventInternal.ifPresent(event -> { |
| event.mCountFilteredUserTyping = countFilteredUserTyping; |
| }); |
| } |
| |
| public void maybeSetCountNotShownImePresentationNotDrawn( |
| int countNotShownImePresentationNotDrawn) { |
| mEventInternal.ifPresent(event -> { |
| event.mCountNotShownImePresentationNotDrawn = countNotShownImePresentationNotDrawn; |
| }); |
| } |
| |
| public void maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen) { |
| mEventInternal.ifPresent(event -> { |
| event.mCountNotShownImeUserNotSeen = countNotShownImeUserNotSeen; |
| }); |
| } |
| |
| public void maybeSetDisplayPresentationType(@UiType int uiType) { |
| mEventInternal.ifPresent(event -> { |
| event.mDisplayPresentationType = getDisplayPresentationType(uiType); |
| }); |
| } |
| |
| public void maybeSetFillRequestSentTimestampMs(int timestamp) { |
| mEventInternal.ifPresent(event -> { |
| event.mFillRequestSentTimestampMs = timestamp; |
| }); |
| } |
| |
| public void maybeSetFillResponseReceivedTimestampMs(int timestamp) { |
| mEventInternal.ifPresent(event -> { |
| event.mFillResponseReceivedTimestampMs = timestamp; |
| }); |
| } |
| |
| public void maybeSetSuggestionSentTimestampMs(int timestamp) { |
| mEventInternal.ifPresent(event -> { |
| event.mSuggestionSentTimestampMs = timestamp; |
| }); |
| } |
| |
| public void maybeSetSuggestionPresentedTimestampMs(int timestamp) { |
| mEventInternal.ifPresent(event -> { |
| event.mSuggestionPresentedTimestampMs = timestamp; |
| }); |
| } |
| |
| public void maybeSetSelectedDatasetId(int selectedDatasetId) { |
| mEventInternal.ifPresent(event -> { |
| event.mSelectedDatasetId = selectedDatasetId; |
| }); |
| } |
| |
| public void maybeSetDialogDismissed(boolean dialogDismissed) { |
| mEventInternal.ifPresent(event -> { |
| event.mDialogDismissed = dialogDismissed; |
| }); |
| } |
| |
| public void maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked) { |
| mEventInternal.ifPresent(event -> { |
| event.mNegativeCtaButtonClicked = negativeCtaButtonClicked; |
| }); |
| } |
| |
| public void maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked) { |
| mEventInternal.ifPresent(event -> { |
| event.mPositiveCtaButtonClicked = positiveCtaButtonClicked; |
| }); |
| } |
| |
| public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) { |
| mEventInternal.ifPresent(event -> { |
| event.mDisplayPresentationType = |
| AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; |
| String imeString = Settings.Secure.getStringForUser(context.getContentResolver(), |
| Settings.Secure.DEFAULT_INPUT_METHOD, userId); |
| if (TextUtils.isEmpty(imeString)) { |
| Slog.w(TAG, "No default IME found"); |
| return; |
| } |
| ComponentName imeComponent = ComponentName.unflattenFromString(imeString); |
| if (imeComponent == null) { |
| Slog.w(TAG, "No default IME found"); |
| return; |
| } |
| int imeUid; |
| String packageName = imeComponent.getPackageName(); |
| try { |
| imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName, |
| PackageManager.ApplicationInfoFlags.of(0), userId).uid; |
| } catch (PackageManager.NameNotFoundException e) { |
| Slog.w(TAG, "Couldn't find packageName: " + packageName); |
| return; |
| } |
| event.mInlineSuggestionHostUid = imeUid; |
| }); |
| } |
| |
| public void maybeSetAutofillServiceUid(int uid) { |
| mEventInternal.ifPresent(event -> { |
| event.mAutofillServiceUid = uid; |
| }); |
| } |
| |
| public void maybeSetIsNewRequest(boolean isRequestTriggered) { |
| mEventInternal.ifPresent(event -> { |
| event.mIsRequestTriggered = isRequestTriggered; |
| }); |
| } |
| |
| /** |
| * Set authentication_type as long as mEventInternal presents. |
| */ |
| public void maybeSetAuthenticationType(@AuthenticationType int val) { |
| mEventInternal.ifPresent(event -> { |
| event.mAuthenticationType = val; |
| }); |
| } |
| |
| /** |
| * Set authentication_result as long as mEventInternal presents. |
| */ |
| public void maybeSetAuthenticationResult(@AuthenticationResult int val) { |
| mEventInternal.ifPresent(event -> { |
| event.mAuthenticationResult = val; |
| }); |
| } |
| |
| /** |
| * Set latency_authentication_ui_display_millis as long as mEventInternal presents. |
| */ |
| public void maybeSetLatencyAuthenticationUiDisplayMillis(int val) { |
| mEventInternal.ifPresent(event -> { |
| event.mLatencyAuthenticationUiDisplayMillis = val; |
| }); |
| } |
| |
| /** |
| * Set latency_dataset_display_millis as long as mEventInternal presents. |
| */ |
| public void maybeSetLatencyDatasetDisplayMillis(int val) { |
| mEventInternal.ifPresent(event -> { |
| event.mLatencyDatasetDisplayMillis = val; |
| }); |
| } |
| |
| /** |
| * Set available_pcc_count. |
| */ |
| public void maybeSetAvailablePccCount(int val) { |
| mEventInternal.ifPresent(event -> { |
| event.mAvailablePccCount = val; |
| }); |
| } |
| |
| /** |
| * Set available_pcc_only_count. |
| */ |
| public void maybeSetAvailablePccOnlyCount(int val) { |
| mEventInternal.ifPresent(event -> { |
| event.mAvailablePccOnlyCount = val; |
| }); |
| } |
| |
| /** |
| * Set selected_dataset_picked_reason. |
| */ |
| public void maybeSetSelectedDatasetPickReason(@Dataset.DatasetEligibleReason int val) { |
| mEventInternal.ifPresent(event -> { |
| event.mSelectedDatasetPickedReason = convertDatasetPickReason(val); |
| }); |
| } |
| |
| /** |
| * Set detection_pref |
| */ |
| public void maybeSetDetectionPreference(@DetectionPreference int detectionPreference) { |
| mEventInternal.ifPresent(event -> { |
| event.mDetectionPreference = detectionPreference; |
| }); |
| } |
| |
| private int convertDatasetPickReason(@Dataset.DatasetEligibleReason int val) { |
| switch (val) { |
| case 0: |
| case 1: |
| case 2: |
| case 3: |
| case 4: |
| case 5: |
| return val; |
| } |
| return PICK_REASON_UNKNOWN; |
| } |
| |
| /** |
| * Set field_classification_request_id as long as mEventInternal presents. |
| */ |
| public void maybeSetFieldClassificationRequestId(int requestId) { |
| mEventInternal.ifPresent(event -> { |
| event.mFieldClassificationRequestId = requestId; |
| }); |
| } |
| |
| public void logAndEndEvent() { |
| if (!mEventInternal.isPresent()) { |
| Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same " |
| + "event"); |
| return; |
| } |
| PresentationStatsEventInternal event = mEventInternal.get(); |
| if (sVerbose) { |
| Slog.v(TAG, "Log AutofillPresentationEventReported:" |
| + " requestId=" + event.mRequestId |
| + " sessionId=" + mSessionId |
| + " mNoPresentationEventReason=" + event.mNoPresentationReason |
| + " mAvailableCount=" + event.mAvailableCount |
| + " mCountShown=" + event.mCountShown |
| + " mCountFilteredUserTyping=" + event.mCountFilteredUserTyping |
| + " mCountNotShownImePresentationNotDrawn=" |
| + event.mCountNotShownImePresentationNotDrawn |
| + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen |
| + " mDisplayPresentationType=" + event.mDisplayPresentationType |
| + " mAutofillServiceUid=" + event.mAutofillServiceUid |
| + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid |
| + " mIsRequestTriggered=" + event.mIsRequestTriggered |
| + " mFillRequestSentTimestampMs=" + event.mFillRequestSentTimestampMs |
| + " mFillResponseReceivedTimestampMs=" + event.mFillResponseReceivedTimestampMs |
| + " mSuggestionSentTimestampMs=" + event.mSuggestionSentTimestampMs |
| + " mSuggestionPresentedTimestampMs=" + event.mSuggestionPresentedTimestampMs |
| + " mSelectedDatasetId=" + event.mSelectedDatasetId |
| + " mDialogDismissed=" + event.mDialogDismissed |
| + " mNegativeCtaButtonClicked=" + event.mNegativeCtaButtonClicked |
| + " mPositiveCtaButtonClicked=" + event.mPositiveCtaButtonClicked |
| + " mAuthenticationType=" + event.mAuthenticationType |
| + " mAuthenticationResult=" + event.mAuthenticationResult |
| + " mLatencyAuthenticationUiDisplayMillis=" |
| + event.mLatencyAuthenticationUiDisplayMillis |
| + " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis |
| + " mAvailablePccCount=" + event.mAvailablePccCount |
| + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount |
| + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason |
| + " mDetectionPreference=" + event.mDetectionPreference |
| + " mFieldClassificationRequestId=" + event.mFieldClassificationRequestId |
| + " mAppPackageUid=" + mCallingAppUid); |
| } |
| |
| // TODO(b/234185326): Distinguish empty responses from other no presentation reasons. |
| if (!event.mIsDatasetAvailable) { |
| mEventInternal = Optional.empty(); |
| return; |
| } |
| FrameworkStatsLog.write( |
| AUTOFILL_PRESENTATION_EVENT_REPORTED, |
| event.mRequestId, |
| mSessionId, |
| event.mNoPresentationReason, |
| event.mAvailableCount, |
| event.mCountShown, |
| event.mCountFilteredUserTyping, |
| event.mCountNotShownImePresentationNotDrawn, |
| event.mCountNotShownImeUserNotSeen, |
| event.mDisplayPresentationType, |
| event.mAutofillServiceUid, |
| event.mInlineSuggestionHostUid, |
| event.mIsRequestTriggered, |
| event.mFillRequestSentTimestampMs, |
| event.mFillResponseReceivedTimestampMs, |
| event.mSuggestionSentTimestampMs, |
| event.mSuggestionPresentedTimestampMs, |
| event.mSelectedDatasetId, |
| event.mDialogDismissed, |
| event.mNegativeCtaButtonClicked, |
| event.mPositiveCtaButtonClicked, |
| event.mAuthenticationType, |
| event.mAuthenticationResult, |
| event.mLatencyAuthenticationUiDisplayMillis, |
| event.mLatencyDatasetDisplayMillis, |
| event.mAvailablePccCount, |
| event.mAvailablePccOnlyCount, |
| event.mSelectedDatasetPickedReason, |
| event.mDetectionPreference, |
| event.mFieldClassificationRequestId, |
| mCallingAppUid); |
| mEventInternal = Optional.empty(); |
| } |
| |
| private static final class PresentationStatsEventInternal { |
| int mRequestId; |
| @NotShownReason int mNoPresentationReason = NOT_SHOWN_REASON_UNKNOWN; |
| boolean mIsDatasetAvailable; |
| int mAvailableCount; |
| int mCountShown; |
| int mCountFilteredUserTyping; |
| int mCountNotShownImePresentationNotDrawn; |
| int mCountNotShownImeUserNotSeen; |
| int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; |
| int mAutofillServiceUid = -1; |
| int mInlineSuggestionHostUid = -1; |
| boolean mIsRequestTriggered; |
| int mFillRequestSentTimestampMs; |
| int mFillResponseReceivedTimestampMs; |
| int mSuggestionSentTimestampMs; |
| int mSuggestionPresentedTimestampMs; |
| int mSelectedDatasetId = -1; |
| boolean mDialogDismissed = false; |
| boolean mNegativeCtaButtonClicked = false; |
| boolean mPositiveCtaButtonClicked = false; |
| int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN; |
| int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN; |
| int mLatencyAuthenticationUiDisplayMillis = -1; |
| int mLatencyDatasetDisplayMillis = -1; |
| int mAvailablePccCount = -1; |
| int mAvailablePccOnlyCount = -1; |
| @DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN; |
| @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN; |
| int mFieldClassificationRequestId = -1; |
| |
| PresentationStatsEventInternal() {} |
| } |
| |
| static int getNoPresentationEventReason( |
| @AutofillManager.AutofillCommitReason int commitReason) { |
| switch (commitReason) { |
| case COMMIT_REASON_VIEW_COMMITTED: |
| return NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY; |
| case COMMIT_REASON_ACTIVITY_FINISHED: |
| return NOT_SHOWN_REASON_ACTIVITY_FINISHED; |
| case COMMIT_REASON_VIEW_CHANGED: |
| return NOT_SHOWN_REASON_VIEW_CHANGED; |
| case COMMIT_REASON_VIEW_CLICKED: |
| // TODO(b/234185326): Add separate reason for view clicked. |
| default: |
| return NOT_SHOWN_REASON_UNKNOWN; |
| } |
| } |
| |
| private static int getDisplayPresentationType(@UiType int uiType) { |
| switch (uiType) { |
| case UI_TYPE_MENU: |
| return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU; |
| case UI_TYPE_INLINE: |
| return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE; |
| case UI_TYPE_DIALOG: |
| return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG; |
| default: |
| return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE; |
| } |
| } |
| } |