• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.autofill;
18 
19 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
20 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
21 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
22 import static android.service.autofill.FillEventHistory.Event.UiType;
23 import static android.view.autofill.AutofillManager.COMMIT_REASON_ACTIVITY_FINISHED;
24 import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CHANGED;
25 import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CLICKED;
26 import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_COMMITTED;
27 
28 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
29 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
30 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
31 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED;
32 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE;
33 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN;
34 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS;
35 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN;
36 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION;
37 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION;
38 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
39 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
40 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
41 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
42 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_DELAY_AFTER_ANIMATION_END;
43 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_FILL_DIALOG_DISABLED;
44 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_LAST_TRIGGERED_ID_CHANGED;
45 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_SCREEN_HAS_CREDMAN_FIELD;
46 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_AFTER_DELAY;
47 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_SINCE_IME_ANIMATED;
48 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_UNKNOWN;
49 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_WAIT_FOR_IME_ANIMATION;
50 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
51 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
52 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED;
53 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS;
54 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
55 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
56 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SUGGESTION_FILTER_OUT;
57 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
58 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
59 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE;
60 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
61 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC;
62 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY;
63 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER;
64 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY;
65 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC;
66 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN;
67 import static com.android.server.autofill.Helper.sVerbose;
68 
69 import android.annotation.IntDef;
70 import android.annotation.NonNull;
71 import android.annotation.Nullable;
72 import android.content.ComponentName;
73 import android.content.Context;
74 import android.content.pm.PackageManager;
75 import android.os.SystemClock;
76 import android.provider.Settings;
77 import android.service.autofill.Dataset;
78 import android.text.TextUtils;
79 import android.util.ArraySet;
80 import android.util.Slog;
81 import android.view.autofill.AutofillId;
82 import android.view.autofill.AutofillManager;
83 import android.view.autofill.AutofillValue;
84 
85 import com.android.internal.util.FrameworkStatsLog;
86 
87 import java.lang.annotation.Retention;
88 import java.lang.annotation.RetentionPolicy;
89 import java.util.List;
90 import java.util.Optional;
91 
92 /** Helper class to track and log Autofill presentation stats. */
93 public final class PresentationStatsEventLogger {
94     private static final String TAG = "PresentationStatsEventLogger";
95 
96     /**
97      * Reasons why presentation was not shown. These are wrappers around
98      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}.
99      */
100     @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = {
101             NOT_SHOWN_REASON_ANY_SHOWN,
102             NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED,
103             NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE,
104             NOT_SHOWN_REASON_VIEW_CHANGED,
105             NOT_SHOWN_REASON_ACTIVITY_FINISHED,
106             NOT_SHOWN_REASON_REQUEST_TIMEOUT,
107             NOT_SHOWN_REASON_REQUEST_FAILED,
108             NOT_SHOWN_REASON_NO_FOCUS,
109             NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY,
110             NOT_SHOWN_REASON_SUGGESTION_FILTERED,
111             NOT_SHOWN_REASON_UNKNOWN
112     })
113     @Retention(RetentionPolicy.SOURCE)
114     public @interface NotShownReason {}
115 
116     /**
117      * Reasons why presentation was not shown. These are wrappers around
118      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationType}.
119      */
120     @IntDef(prefix = {"AUTHENTICATION_TYPE"}, value = {
121             AUTHENTICATION_TYPE_UNKNOWN,
122             AUTHENTICATION_TYPE_DATASET_AUTHENTICATION,
123             AUTHENTICATION_TYPE_FULL_AUTHENTICATION
124     })
125     @Retention(RetentionPolicy.SOURCE)
126     public @interface AuthenticationType {
127     }
128 
129     /**
130      * Reasons why presentation was not shown. These are wrappers around
131      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationResult}.
132      */
133     @IntDef(prefix = {"AUTHENTICATION_RESULT"}, value = {
134             AUTHENTICATION_RESULT_UNKNOWN,
135             AUTHENTICATION_RESULT_SUCCESS,
136             AUTHENTICATION_RESULT_FAILURE
137     })
138     @Retention(RetentionPolicy.SOURCE)
139     public @interface AuthenticationResult {
140     }
141 
142     /**
143      * Reasons why the picked dataset was present. These are wrappers around
144      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DatasetPickedReason}.
145      * This enum is similar to {@link android.service.autofill.Dataset.DatasetEligibleReason}
146      */
147     @IntDef(prefix = {"PICK_REASON"}, value = {
148             PICK_REASON_UNKNOWN,
149             PICK_REASON_NO_PCC,
150             PICK_REASON_PROVIDER_DETECTION_ONLY,
151             PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC,
152             PICK_REASON_PCC_DETECTION_ONLY,
153             PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER,
154     })
155     @Retention(RetentionPolicy.SOURCE)
156     public @interface DatasetPickedReason {}
157 
158     /**
159      * The type of detection that was preferred. These are wrappers around
160      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DetectionPreference}.
161      */
162     @IntDef(prefix = {"DETECTION_PREFER"}, value = {
163             DETECTION_PREFER_UNKNOWN,
164             DETECTION_PREFER_AUTOFILL_PROVIDER,
165             DETECTION_PREFER_PCC
166     })
167     @Retention(RetentionPolicy.SOURCE)
168     public @interface DetectionPreference {}
169 
170     /**
171      * The fill dialog not shown reason. These are wrappers around
172      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.FillDialogNotShownReason}.
173      */
174     @IntDef(prefix = {"FILL_DIALOG_NOT_SHOWN_REASON"}, value = {
175         FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN,
176         FILL_DIALOG_NOT_SHOWN_REASON_FILL_DIALOG_DISABLED,
177         FILL_DIALOG_NOT_SHOWN_REASON_SCREEN_HAS_CREDMAN_FIELD,
178         FILL_DIALOG_NOT_SHOWN_REASON_LAST_TRIGGERED_ID_CHANGED,
179         FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION,
180         FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED,
181         FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END,
182         FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_AFTER_DELAY
183     })
184     @Retention(RetentionPolicy.SOURCE)
185     public @interface FillDialogNotShownReason {}
186 
187     public static final int NOT_SHOWN_REASON_ANY_SHOWN =
188             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
189     public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED =
190             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
191     public static final int NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE =
192             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE;
193     public static final int NOT_SHOWN_REASON_VIEW_CHANGED =
194             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
195     public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED =
196             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
197     public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT =
198             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
199     public static final int NOT_SHOWN_REASON_REQUEST_FAILED =
200             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED;
201     public static final int NOT_SHOWN_REASON_NO_FOCUS =
202             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS;
203     public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY =
204             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
205     public static final int NOT_SHOWN_REASON_UNKNOWN =
206             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
207     public static final int NOT_SHOWN_REASON_SUGGESTION_FILTERED =
208             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SUGGESTION_FILTER_OUT;
209 
210     public static final int AUTHENTICATION_TYPE_UNKNOWN =
211             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN;
212     public static final int AUTHENTICATION_TYPE_DATASET_AUTHENTICATION =
213             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION;
214     public static final int AUTHENTICATION_TYPE_FULL_AUTHENTICATION =
215             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION;
216 
217     public static final int AUTHENTICATION_RESULT_UNKNOWN =
218             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN;
219     public static final int AUTHENTICATION_RESULT_SUCCESS =
220             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS;
221     public static final int AUTHENTICATION_RESULT_FAILURE =
222             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE;
223 
224     public static final int PICK_REASON_UNKNOWN =
225             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN;
226     public static final int PICK_REASON_NO_PCC =
227             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC;
228      public static final int PICK_REASON_PROVIDER_DETECTION_ONLY =
229              AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY;
230     public static final int PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC =
231             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC;
232     public static final int PICK_REASON_PCC_DETECTION_ONLY =
233             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY;
234     public static final int PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER =
235             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER;
236 
237 
238     // Values for AutofillFillResponseReported.detection_preference
239     public static final int DETECTION_PREFER_UNKNOWN =
240             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
241     public static final int DETECTION_PREFER_AUTOFILL_PROVIDER =
242             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
243     public static final int DETECTION_PREFER_PCC =
244             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
245 
246     // Values for AutofillFillResponseReported.fill_dialog_not_shown_reason
247     public static final int FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN =
248             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_UNKNOWN;
249     public static final int FILL_DIALOG_NOT_SHOWN_REASON_FILL_DIALOG_DISABLED =
250             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_FILL_DIALOG_DISABLED;
251     public static final int FILL_DIALOG_NOT_SHOWN_REASON_SCREEN_HAS_CREDMAN_FIELD =
252             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_SCREEN_HAS_CREDMAN_FIELD;
253     public static final int FILL_DIALOG_NOT_SHOWN_REASON_LAST_TRIGGERED_ID_CHANGED =
254             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_LAST_TRIGGERED_ID_CHANGED;
255     public static final int FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION =
256             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_WAIT_FOR_IME_ANIMATION;
257     public static final int FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED =
258             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_SINCE_IME_ANIMATED;
259     public static final int FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END =
260             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_DELAY_AFTER_ANIMATION_END;
261     public static final int FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_AFTER_DELAY =
262             AUTOFILL_PRESENTATION_EVENT_REPORTED__FILL_DIALOG_NOT_SHOWN_REASON__REASON_TIMEOUT_AFTER_DELAY;
263 
264 
265     private static final int DEFAULT_VALUE_INT = -1;
266 
267     private final int mSessionId;
268     /**
269      * For app_package_uid.
270      */
271     private final int mCallingAppUid;
272     private Optional<PresentationStatsEventInternal> mEventInternal;
273     private final long mSessionStartTimestamp;
274 
PresentationStatsEventLogger(int sessionId, int callingAppUid, long timestamp)275     private PresentationStatsEventLogger(int sessionId, int callingAppUid, long timestamp) {
276         mSessionId = sessionId;
277         mCallingAppUid = callingAppUid;
278         mSessionStartTimestamp = timestamp;
279         mEventInternal = Optional.empty();
280     }
281 
282     /**
283      * Create PresentationStatsEventLogger, populated with sessionId and the callingAppUid
284      */
createPresentationLog( int sessionId, int callingAppUid, long timestamp)285     public static PresentationStatsEventLogger createPresentationLog(
286             int sessionId, int callingAppUid, long timestamp) {
287         return new PresentationStatsEventLogger(sessionId, callingAppUid, timestamp);
288     }
289 
startNewEvent()290     public void startNewEvent() {
291         if (mEventInternal.isPresent()) {
292             Slog.e(TAG, "Failed to start new event because already have active event.");
293             return;
294         }
295         Slog.d(TAG, "Started new PresentationStatsEvent");
296         mEventInternal = Optional.of(new PresentationStatsEventInternal());
297     }
298 
299     /**
300      * Test use only, returns a copy of the events object
301      */
getInternalEvent()302     Optional<PresentationStatsEventInternal> getInternalEvent() {
303         return mEventInternal;
304     }
305 
306     /**
307      * Set request_id
308      */
maybeSetRequestId(int requestId)309     public void maybeSetRequestId(int requestId) {
310         mEventInternal.ifPresent(event -> event.mRequestId = requestId);
311     }
312 
313     /**
314      * Set is_credential_request
315      */
maybeSetIsCredentialRequest(boolean isCredentialRequest)316     public void maybeSetIsCredentialRequest(boolean isCredentialRequest) {
317         mEventInternal.ifPresent(event -> event.mIsCredentialRequest = isCredentialRequest);
318     }
319 
320     /**
321      * Set webview_requested_credential
322      */
maybeSetWebviewRequestedCredential(boolean webviewRequestedCredential)323     public void maybeSetWebviewRequestedCredential(boolean webviewRequestedCredential) {
324         mEventInternal.ifPresent(event ->
325                 event.mWebviewRequestedCredential = webviewRequestedCredential);
326     }
327 
maybeSetNoPresentationEventReason(@otShownReason int reason)328     public void maybeSetNoPresentationEventReason(@NotShownReason int reason) {
329         mEventInternal.ifPresent(event -> {
330             if (event.mCountShown == 0) {
331                 event.mNoPresentationReason = reason;
332             }
333         });
334     }
335 
336     /**
337      * Call this when first entering the View. It will check if there are pre-existing characters
338      * in the view, and sets NOT_SHOWN_REASON_SUGGESTION_FILTERED if there is
339      */
maybeSetNoPresentationEventReasonSuggestionsFiltered(AutofillValue value)340     public void maybeSetNoPresentationEventReasonSuggestionsFiltered(AutofillValue value) {
341         mEventInternal.ifPresent(
342                 event -> {
343                     if (value == null || !value.isText()) {
344                         return;
345                     }
346 
347                     int length = value.getTextValue().length();
348 
349                     if (length > 0) {
350                         maybeSetNoPresentationEventReason(NOT_SHOWN_REASON_SUGGESTION_FILTERED);
351                     }
352                 });
353     }
354 
maybeSetNoPresentationEventReasonIfNoReasonExists(@otShownReason int reason)355     public void maybeSetNoPresentationEventReasonIfNoReasonExists(@NotShownReason int reason) {
356         mEventInternal.ifPresent(
357                 event -> {
358                     if (event.mCountShown != 0) {
359                         return;
360                     }
361 
362                     // The only events that can be overwritten.
363                     // NOT_SHOWN_REASON_UNKNOWN is the default for inline/dropdown
364                     // NOT_SHOWN_REASON_NO_FOCUS is the default for fill dialog
365                     if (event.mNoPresentationReason != NOT_SHOWN_REASON_UNKNOWN
366                             || event.mNoPresentationReason != NOT_SHOWN_REASON_NO_FOCUS) {
367                         Slog.d(TAG, "Not setting no presentation reason because it already exists");
368                         return;
369                     }
370 
371                     event.mNoPresentationReason = reason;
372                 });
373     }
374 
maybeSetAvailableCount(@ullable List<Dataset> datasetList, AutofillId currentViewId)375     public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList,
376             AutofillId currentViewId) {
377         mEventInternal.ifPresent(event -> {
378             CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId);
379             event.mAvailableCount = container.mAvailableCount;
380             event.mAvailablePccCount = container.mAvailablePccCount;
381             event.mAvailablePccOnlyCount = container.mAvailablePccOnlyCount;
382             event.mIsDatasetAvailable = container.mAvailableCount > 0;
383         });
384     }
385 
386     /**
387      * Called for inline suggestions - inflated one at
388      * a time. If InlineSuggestions were filtered,
389      * reset the count be incrementing
390      */
maybeIncrementCountShown()391     public void maybeIncrementCountShown() {
392         mEventInternal.ifPresent(event -> {
393             if (event.shouldResetShownCount) {
394                 event.shouldResetShownCount = false;
395                 event.mCountShown = 0;
396             }
397 
398             if (event.mCountShown == 0) {
399                 // The first time suggestions are rendered
400                 // set time stamp
401                 maybeSetSuggestionPresentedTimestampMs();
402             }
403 
404             event.mCountShown += 1;
405         });
406     }
407 
408     /**
409      * Call this when UI is hidden. This will set a flag to reset count for inline. We do this
410      * instead of resetting right away in case there are 0 inline presentations after.
411      */
markShownCountAsResettable()412     public void markShownCountAsResettable() {
413         mEventInternal.ifPresent(event -> {
414             event.shouldResetShownCount = true;
415         });
416     }
417 
maybeSetCountShown(@ullable List<Dataset> datasetList, AutofillId currentViewId)418     public void maybeSetCountShown(@Nullable List<Dataset> datasetList,
419             AutofillId currentViewId) {
420         mEventInternal.ifPresent(event -> {
421             CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId);
422             event.mCountShown = container.mAvailableCount;
423             if (container.mAvailableCount > 0) {
424                 event.mNoPresentationReason = NOT_SHOWN_REASON_ANY_SHOWN;
425             }
426         });
427     }
428 
429     /**
430      * This is called when a dataset is shown to the user. Will set the count shown,
431      * related timestamps and presentation reason.
432      */
logWhenDatasetShown(int datasets)433     public void logWhenDatasetShown(int datasets) {
434         mEventInternal.ifPresent(
435                 event -> {
436                     maybeSetSuggestionPresentedTimestampMs();
437                     event.mCountShown = datasets;
438                     event.mNoPresentationReason = NOT_SHOWN_REASON_ANY_SHOWN;
439                 });
440     }
441 
getDatasetCountForAutofillId(@ullable List<Dataset> datasetList, AutofillId currentViewId)442     private static CountContainer getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList,
443             AutofillId currentViewId) {
444 
445         CountContainer container = new CountContainer();
446         if (datasetList != null) {
447             for (int i = 0; i < datasetList.size(); i++) {
448                 Dataset data = datasetList.get(i);
449                 if (data != null && data.getFieldIds() != null
450                         && data.getFieldIds().contains(currentViewId)) {
451                     container.mAvailableCount += 1;
452                     if (data.getEligibleReason() == PICK_REASON_PCC_DETECTION_ONLY) {
453                         container.mAvailablePccOnlyCount++;
454                         container.mAvailablePccCount++;
455                     } else if (data.getEligibleReason()
456                             == PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER) {
457                         container.mAvailablePccCount++;
458                     }
459                 }
460             }
461         }
462         return container;
463     }
464 
465     private static class CountContainer{
466         int mAvailableCount = 0;
467         int mAvailablePccCount = 0;
468         int mAvailablePccOnlyCount = 0;
469 
CountContainer()470         CountContainer() {}
471 
CountContainer(int availableCount, int availablePccCount, int availablePccOnlyCount)472         CountContainer(int availableCount, int availablePccCount,
473                 int availablePccOnlyCount) {
474             mAvailableCount = availableCount;
475             mAvailablePccCount = availablePccCount;
476             mAvailablePccOnlyCount = availablePccOnlyCount;
477         }
478     }
479 
maybeSetCountFilteredUserTyping(int countFilteredUserTyping)480     public void maybeSetCountFilteredUserTyping(int countFilteredUserTyping) {
481         mEventInternal.ifPresent(event -> {
482             event.mCountFilteredUserTyping = countFilteredUserTyping;
483         });
484     }
485 
maybeSetCountNotShownImePresentationNotDrawn( int countNotShownImePresentationNotDrawn)486     public void maybeSetCountNotShownImePresentationNotDrawn(
487             int countNotShownImePresentationNotDrawn) {
488         mEventInternal.ifPresent(event -> {
489             event.mCountNotShownImePresentationNotDrawn = countNotShownImePresentationNotDrawn;
490         });
491     }
492 
maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen)493     public void maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen) {
494         mEventInternal.ifPresent(event -> {
495             event.mCountNotShownImeUserNotSeen = countNotShownImeUserNotSeen;
496         });
497     }
498 
maybeSetDisplayPresentationType(@iType int uiType)499     public void maybeSetDisplayPresentationType(@UiType int uiType) {
500         mEventInternal.ifPresent(event -> {
501             // There are cases in which another UI type will show up after selects a dataset
502             // such as with Inline after Fill Dialog. Set as the first presentation type only.
503             if (event.mDisplayPresentationType
504                     == AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE) {
505                 event.mDisplayPresentationType = getDisplayPresentationType(uiType);
506             }
507         });
508     }
509 
maybeSetFillRequestSentTimestampMs(int timestamp)510     public void maybeSetFillRequestSentTimestampMs(int timestamp) {
511         mEventInternal.ifPresent(event -> {
512             event.mFillRequestSentTimestampMs = timestamp;
513         });
514     }
515 
maybeSetFillRequestSentTimestampMs()516     public void maybeSetFillRequestSentTimestampMs() {
517         maybeSetFillRequestSentTimestampMs(getElapsedTime());
518     }
519 
maybeSetFillResponseReceivedTimestampMs(int timestamp)520     public void maybeSetFillResponseReceivedTimestampMs(int timestamp) {
521         mEventInternal.ifPresent(event -> {
522             event.mFillResponseReceivedTimestampMs = timestamp;
523         });
524     }
525 
maybeSetFillResponseReceivedTimestampMs()526     public void maybeSetFillResponseReceivedTimestampMs() {
527         maybeSetFillResponseReceivedTimestampMs(getElapsedTime());
528     }
529 
maybeSetSuggestionSentTimestampMs(int timestamp)530     public void maybeSetSuggestionSentTimestampMs(int timestamp) {
531         mEventInternal.ifPresent(
532                 event -> {
533                     if (event.mSuggestionSentTimestampMs == DEFAULT_VALUE_INT) {
534                         event.mSuggestionSentTimestampMs = timestamp;
535                     }
536                 });
537     }
538 
maybeSetSuggestionSentTimestampMs()539     public void maybeSetSuggestionSentTimestampMs() {
540         maybeSetSuggestionSentTimestampMs(getElapsedTime());
541     }
542 
maybeSetSuggestionPresentedTimestampMs(int timestamp)543     public void maybeSetSuggestionPresentedTimestampMs(int timestamp) {
544         mEventInternal.ifPresent(event -> {
545             // mSuggestionPresentedTimestampMs only tracks the first suggested timestamp.
546             if (event.mSuggestionPresentedTimestampMs == DEFAULT_VALUE_INT) {
547                 event.mSuggestionPresentedTimestampMs = timestamp;
548             }
549 
550             event.mSuggestionPresentedLastTimestampMs = timestamp;
551         });
552     }
553 
maybeSetSuggestionPresentedTimestampMs()554     public void maybeSetSuggestionPresentedTimestampMs() {
555         maybeSetSuggestionPresentedTimestampMs(getElapsedTime());
556     }
557 
maybeSetSelectedDatasetId(int selectedDatasetId)558     public void maybeSetSelectedDatasetId(int selectedDatasetId) {
559         mEventInternal.ifPresent(event -> {
560             event.mSelectedDatasetId = selectedDatasetId;
561         });
562         setPresentationSelectedTimestamp();
563     }
564 
maybeSetDialogDismissed(boolean dialogDismissed)565     public void maybeSetDialogDismissed(boolean dialogDismissed) {
566         mEventInternal.ifPresent(event -> {
567             event.mDialogDismissed = dialogDismissed;
568         });
569     }
570 
maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked)571     public void maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked) {
572         mEventInternal.ifPresent(event -> {
573             event.mNegativeCtaButtonClicked = negativeCtaButtonClicked;
574         });
575     }
576 
maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked)577     public void maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked) {
578         mEventInternal.ifPresent(event -> {
579             event.mPositiveCtaButtonClicked = positiveCtaButtonClicked;
580         });
581     }
582 
maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId)583     public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) {
584         mEventInternal.ifPresent(event -> {
585             String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
586                     Settings.Secure.DEFAULT_INPUT_METHOD, userId);
587             if (TextUtils.isEmpty(imeString)) {
588                 Slog.w(TAG, "No default IME found");
589                 return;
590             }
591             ComponentName imeComponent = ComponentName.unflattenFromString(imeString);
592             if (imeComponent == null) {
593                 Slog.w(TAG, "No default IME found");
594                 return;
595             }
596             int imeUid;
597             String packageName = imeComponent.getPackageName();
598             try {
599                 imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName,
600                         PackageManager.ApplicationInfoFlags.of(0), userId).uid;
601             } catch (PackageManager.NameNotFoundException e) {
602                 Slog.w(TAG, "Couldn't find packageName: " + packageName);
603                 return;
604             }
605             event.mInlineSuggestionHostUid = imeUid;
606         });
607     }
608 
maybeSetAutofillServiceUid(int uid)609     public void maybeSetAutofillServiceUid(int uid) {
610         mEventInternal.ifPresent(event -> {
611             event.mAutofillServiceUid = uid;
612         });
613     }
614 
maybeSetIsNewRequest(boolean isRequestTriggered)615     public void maybeSetIsNewRequest(boolean isRequestTriggered) {
616         mEventInternal.ifPresent(event -> {
617             event.mIsRequestTriggered = isRequestTriggered;
618         });
619     }
620 
621     /**
622      * Set authentication_type as long as mEventInternal presents.
623      */
maybeSetAuthenticationType(@uthenticationType int val)624     public void maybeSetAuthenticationType(@AuthenticationType int val) {
625         mEventInternal.ifPresent(event -> {
626             event.mAuthenticationType = val;
627         });
628     }
629 
630     /**
631      * Set authentication_result as long as mEventInternal presents.
632      */
maybeSetAuthenticationResult(@uthenticationResult int val)633     public void maybeSetAuthenticationResult(@AuthenticationResult int val) {
634         mEventInternal.ifPresent(event -> {
635             event.mAuthenticationResult = val;
636         });
637     }
638 
639     /**
640      * Set latency_authentication_ui_display_millis as long as mEventInternal presents.
641      */
maybeSetLatencyAuthenticationUiDisplayMillis(int val)642     public void maybeSetLatencyAuthenticationUiDisplayMillis(int val) {
643         mEventInternal.ifPresent(event -> {
644             event.mLatencyAuthenticationUiDisplayMillis = val;
645         });
646     }
647 
648     /** Set latency_authentication_ui_display_millis as long as mEventInternal presents. */
maybeSetLatencyAuthenticationUiDisplayMillis()649     public void maybeSetLatencyAuthenticationUiDisplayMillis() {
650         maybeSetLatencyAuthenticationUiDisplayMillis(getElapsedTime());
651     }
652 
653     /**
654      * Set latency_dataset_display_millis as long as mEventInternal presents.
655      */
maybeSetLatencyDatasetDisplayMillis(int val)656     public void maybeSetLatencyDatasetDisplayMillis(int val) {
657         mEventInternal.ifPresent(event -> {
658             event.mLatencyDatasetDisplayMillis = val;
659         });
660     }
661 
662     /** Set latency_dataset_display_millis as long as mEventInternal presents. */
maybeSetLatencyDatasetDisplayMillis()663     public void maybeSetLatencyDatasetDisplayMillis() {
664         maybeSetLatencyDatasetDisplayMillis(getElapsedTime());
665     }
666 
667     /**
668      * Set available_pcc_count.
669      */
maybeSetAvailablePccCount(int val)670     public void maybeSetAvailablePccCount(int val) {
671         mEventInternal.ifPresent(event -> {
672             event.mAvailablePccCount = val;
673         });
674     }
675 
676     /**
677      * Set available_pcc_only_count.
678      */
maybeSetAvailablePccOnlyCount(int val)679     public void maybeSetAvailablePccOnlyCount(int val) {
680         mEventInternal.ifPresent(event -> {
681             event.mAvailablePccOnlyCount = val;
682         });
683     }
684 
685     /**
686      * Set selected_dataset_picked_reason.
687      */
maybeSetSelectedDatasetPickReason(@ataset.DatasetEligibleReason int val)688     public void maybeSetSelectedDatasetPickReason(@Dataset.DatasetEligibleReason int val) {
689         mEventInternal.ifPresent(event -> {
690             event.mSelectedDatasetPickedReason = convertDatasetPickReason(val);
691         });
692     }
693 
694     /**
695      * Set detection_pref
696      */
maybeSetDetectionPreference(@etectionPreference int detectionPreference)697     public void maybeSetDetectionPreference(@DetectionPreference int detectionPreference) {
698         mEventInternal.ifPresent(event -> {
699             event.mDetectionPreference = detectionPreference;
700         });
701     }
702 
703     /**
704      * Sets the field length whenever the text changes. Will keep track of the first
705      * and last modification lengths.
706      */
updateTextFieldLength(AutofillValue value)707     public void updateTextFieldLength(AutofillValue value) {
708         mEventInternal.ifPresent(event -> {
709             if (value == null || !value.isText()) {
710                 return;
711             }
712 
713             int length = value.getTextValue().length();
714 
715             if (event.mFieldFirstLength == DEFAULT_VALUE_INT) {
716                 event.mFieldFirstLength = length;
717             }
718             event.mFieldLastLength = length;
719         });
720     }
721 
722     /**
723      * Set various timestamps whenever the ViewState is modified
724      *
725      * <p>If the ViewState contains ViewState.STATE_AUTOFILLED, sets field_autofilled_timestamp_ms
726      * else, set field_first_modified_timestamp_ms (if unset) and field_last_modified_timestamp_ms
727      */
onFieldTextUpdated(ViewState state, AutofillValue value)728     public void onFieldTextUpdated(ViewState state, AutofillValue value) {
729         mEventInternal.ifPresent(event -> {
730             int timestamp = getElapsedTime();
731             // Focused id should be set before this is called
732             if (state == null || state.id == null || state.id.getViewId() != event.mFocusedId) {
733                 // if these don't match, the currently field different than before
734                 Slog.w(
735                         TAG,
736                         "Bad view state for: " + event.mFocusedId + ", state: " + state);
737                 return;
738             }
739 
740             updateTextFieldLength(value);
741 
742             // Text changed because filling into form, just log Autofill timestamp
743             if ((state.getState() & ViewState.STATE_AUTOFILLED) != 0) {
744                 event.mAutofilledTimestampMs = timestamp;
745                 return;
746             }
747 
748 
749             // Set timestamp variables
750             if (event.mFieldModifiedFirstTimestampMs == DEFAULT_VALUE_INT) {
751                 event.mFieldModifiedFirstTimestampMs = timestamp;
752             }
753             event.mFieldModifiedLastTimestampMs = timestamp;
754         });
755     }
756 
setPresentationSelectedTimestamp()757     public void setPresentationSelectedTimestamp() {
758         mEventInternal.ifPresent(event -> {
759             event.mSelectionTimestamp = getElapsedTime();
760         });
761     }
762 
763     /**
764      * Returns timestamp (relative to mSessionStartTimestamp)
765      */
getElapsedTime()766     private int getElapsedTime() {
767         return (int)(SystemClock.elapsedRealtime() - mSessionStartTimestamp);
768     }
769 
770 
convertDatasetPickReason(@ataset.DatasetEligibleReason int val)771     private int convertDatasetPickReason(@Dataset.DatasetEligibleReason int val) {
772         switch (val) {
773             case 0:
774             case 1:
775             case 2:
776             case 3:
777             case 4:
778             case 5:
779                 return val;
780         }
781         return PICK_REASON_UNKNOWN;
782     }
783 
784     /**
785      * Set field_classification_request_id as long as mEventInternal presents.
786      */
maybeSetFieldClassificationRequestId(int requestId)787     public void maybeSetFieldClassificationRequestId(int requestId) {
788         mEventInternal.ifPresent(event -> {
789             event.mFieldClassificationRequestId = requestId;
790         });
791     }
792 
793     /**
794      * Set views_fillable_total_count as long as mEventInternal presents.
795      */
maybeSetViewFillablesAndCount(List<AutofillId> autofillIds)796     public void maybeSetViewFillablesAndCount(List<AutofillId> autofillIds) {
797         mEventInternal.ifPresent(event -> {
798             event.mAutofillIdsAttemptedAutofill = new ArraySet<>(autofillIds);
799             event.mViewFillableTotalCount = event.mAutofillIdsAttemptedAutofill.size();
800         });
801     }
802 
803     /**
804      * Set views_fillable_total_count as long as mEventInternal presents.
805      */
maybeUpdateViewFillablesForRefillAttempt(List<AutofillId> autofillIds)806     public void maybeUpdateViewFillablesForRefillAttempt(List<AutofillId> autofillIds) {
807         mEventInternal.ifPresent(event -> {
808             // These autofill ids would be the ones being re-attempted.
809             event.mAutofillIdsAttemptedAutofill = new ArraySet<>(autofillIds);
810             // These autofill id's are being refilled, so they had failed previously.
811             // Note that these autofillIds correspond to the new autofill ids after relayout.
812             event.mFailedAutofillIds = new ArraySet<>(autofillIds);
813             setHasRelayoutLog();
814         });
815     }
816 
817     /**
818      * Set how many views are filtered from fill because they are not in current session
819      */
maybeSetFilteredFillableViewsCount(int filteredViewsCount)820     public void maybeSetFilteredFillableViewsCount(int filteredViewsCount) {
821         mEventInternal.ifPresent(event -> {
822             event.mFilteredFillabaleViewCount = filteredViewsCount;
823         });
824     }
825 
826     /**
827      * Set views_filled_failure_count using failure count as long as mEventInternal
828      * presents.
829      */
maybeSetViewFillFailureCounts(@onNull List<AutofillId> ids, boolean isRefill)830     public void maybeSetViewFillFailureCounts(@NonNull List<AutofillId> ids, boolean isRefill) {
831         mEventInternal.ifPresent(event -> {
832             int failureCount = ids.size();
833             if (isRefill) {
834                 event.mViewFailedOnRefillCount = failureCount;
835                 setHasRelayoutLog();
836             } else {
837                 event.mViewFillFailureCount = failureCount;
838                 event.mViewFailedPriorToRefillCount = failureCount;
839                 event.mFailedAutofillIds = new ArraySet<>(ids);
840             }
841         });
842     }
843 
844     /** Sets focused_autofill_id using view id */
maybeSetFocusedId(AutofillId id)845     public void maybeSetFocusedId(AutofillId id) {
846         mEventInternal.ifPresent(
847                 event -> {
848                     event.mFocusedId = id.getViewId();
849                     if (id.isVirtualInt()) {
850                         event.mFocusedVirtualAutofillId =
851                                 id.getVirtualChildIntId() % 100;
852                     }
853                 });
854     }
855 
856     /**
857      * Set views_filled_failure_count using failure count as long as mEventInternal
858      * presents.
859      */
maybeAddSuccessId(AutofillId autofillId)860     public synchronized void maybeAddSuccessId(AutofillId autofillId) {
861         mEventInternal.ifPresent(event -> {
862             ArraySet<AutofillId> autofillIds = event.mAutofillIdsAttemptedAutofill;
863             if (autofillIds == null) {
864                 Slog.w(TAG, "Attempted autofill ids is null, but received autofillId:" + autofillId
865                         + " successfully filled");
866                 event.mViewFilledButUnexpectedCount++;
867             } else if (autofillIds.contains(autofillId)) {
868                 ArraySet<AutofillId> failedIds = event.mFailedAutofillIds;
869                 if (failedIds.contains(autofillId)) {
870                     if (sVerbose) {
871                         Slog.v(TAG, "Logging autofill refill of id:" + autofillId);
872                     }
873                     // This indicates the success after refill attempt
874                     event.mViewFilledSuccessfullyOnRefillCount++;
875                     // Remove so if we don't reprocess duplicate requests
876                     failedIds.remove(autofillId);
877                 } else {
878                     if (sVerbose) {
879                         Slog.v(TAG, "Logging autofill for id:" + autofillId);
880                     }
881                 }
882                 // Common actions to take irrespective of being filled by refill attempt or not.
883                 event.mViewFillSuccessCount++;
884                 autofillIds.remove(autofillId);
885                 event.mAlreadyFilledAutofillIds.add(autofillId);
886             } else if (event.mAlreadyFilledAutofillIds.contains(autofillId)) {
887                 if (sVerbose) {
888                     Slog.v(TAG, "Successfully filled autofillId:" + autofillId
889                             + " already processed ");
890                 }
891             } else {
892                 Slog.w(TAG, "Successfully filled autofillId:" + autofillId
893                         + " not found in list of attempted autofill ids: " + autofillIds);
894                 event.mViewFilledButUnexpectedCount++;
895             }
896         });
897     }
898 
899     /**
900      * Set how many views are filtered from fill because they are not in current session
901      */
maybeSetNotifyNotExpiringResponseDuringAuth()902     public void maybeSetNotifyNotExpiringResponseDuringAuth() {
903         mEventInternal.ifPresent(event -> {
904             event.mFixExpireResponseDuringAuthCount++;
905         });
906     }
907     /**
908      * Set how many views are filtered from fill because they are not in current session
909      */
notifyViewEnteredIgnoredDuringAuthCount()910     public void notifyViewEnteredIgnoredDuringAuthCount() {
911         mEventInternal.ifPresent(event -> {
912             event.mNotifyViewEnteredIgnoredDuringAuthCount++;
913         });
914     }
915 
916     /**
917      * Set fill_dialog_not_shown_reason
918      * @param reason
919      */
maybeSetFillDialogNotShownReason(@illDialogNotShownReason int reason)920     public void maybeSetFillDialogNotShownReason(@FillDialogNotShownReason int reason) {
921         mEventInternal.ifPresent(event -> {
922             if ((event.mFillDialogNotShownReason
923                     == FILL_DIALOG_NOT_SHOWN_REASON_DELAY_AFTER_ANIMATION_END
924                     || event.mFillDialogNotShownReason
925                     == FILL_DIALOG_NOT_SHOWN_REASON_WAIT_FOR_IME_ANIMATION) && reason
926                     == FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_SINCE_IME_ANIMATED) {
927                 event.mFillDialogNotShownReason = FILL_DIALOG_NOT_SHOWN_REASON_TIMEOUT_AFTER_DELAY;
928             } else {
929                 event.mFillDialogNotShownReason = reason;
930             }
931         });
932     }
933 
934     /**
935      * Set fill_dialog_ready_to_show_ms
936      * @param val
937      */
maybeSetFillDialogReadyToShowMs(long val)938     public void maybeSetFillDialogReadyToShowMs(long val) {
939         mEventInternal.ifPresent(event -> {
940             event.mFillDialogReadyToShowMs = (int) (val - mSessionStartTimestamp);
941         });
942     }
943 
944     /**
945      * Set ime_animation_finish_ms
946      * @param val
947      */
maybeSetImeAnimationFinishMs(long val)948     public void maybeSetImeAnimationFinishMs(long val) {
949         mEventInternal.ifPresent(event -> {
950             event.mImeAnimationFinishMs = (int) (val - mSessionStartTimestamp);
951         });
952     }
953     /**
954      * Set the log contains relayout metrics.
955      * This is being added as a temporary measure to add logging.
956      * In future, when we map Session's old view states to the new autofill id's as part of fixing
957      * save for relayout cases, we no longer would need this. But till then, this is needed to set
958      * autofill logs for relayout cases.
959      */
setHasRelayoutLog()960     private void setHasRelayoutLog() {
961         mEventInternal.ifPresent(event -> {
962             event.mHasRelayoutLog = true;
963         });
964     }
965 
966     /**
967      * Finish and log the event.
968      */
logAndEndEvent(String caller)969     public void logAndEndEvent(String caller) {
970         if (!mEventInternal.isPresent()) {
971             Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same "
972                     + "event");
973             return;
974         }
975 
976         PresentationStatsEventInternal event = mEventInternal.get();
977         boolean ignoreLogging = !event.mIsDatasetAvailable
978                 && !event.mHasRelayoutLog
979                 && !(event.mFixExpireResponseDuringAuthCount > 0)
980                 && !(event.mNotifyViewEnteredIgnoredDuringAuthCount > 0);
981         if (sVerbose) {
982             Slog.v(TAG, "(" + caller + ") "
983                     + (ignoreLogging ? "IGNORING - following event won't be logged: " : "")
984                     + "Log AutofillPresentationEventReported:"
985                     + " requestId=" + event.mRequestId
986                     + " sessionId=" + mSessionId
987                     + " mNoPresentationEventReason=" + event.mNoPresentationReason
988                     + " mAvailableCount=" + event.mAvailableCount
989                     + " mCountShown=" + event.mCountShown
990                     + " mCountFilteredUserTyping=" + event.mCountFilteredUserTyping
991                     + " mCountNotShownImePresentationNotDrawn="
992                     + event.mCountNotShownImePresentationNotDrawn
993                     + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen
994                     + " mDisplayPresentationType=" + event.mDisplayPresentationType
995                     + " mAutofillServiceUid=" + event.mAutofillServiceUid
996                     + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid
997                     + " mIsRequestTriggered=" + event.mIsRequestTriggered
998                     + " mFillRequestSentTimestampMs=" + event.mFillRequestSentTimestampMs
999                     + " mFillResponseReceivedTimestampMs=" + event.mFillResponseReceivedTimestampMs
1000                     + " mSuggestionSentTimestampMs=" + event.mSuggestionSentTimestampMs
1001                     + " mSuggestionPresentedTimestampMs=" + event.mSuggestionPresentedTimestampMs
1002                     + " mSelectedDatasetId=" + event.mSelectedDatasetId
1003                     + " mDialogDismissed=" + event.mDialogDismissed
1004                     + " mNegativeCtaButtonClicked=" + event.mNegativeCtaButtonClicked
1005                     + " mPositiveCtaButtonClicked=" + event.mPositiveCtaButtonClicked
1006                     + " mAuthenticationType=" + event.mAuthenticationType
1007                     + " mAuthenticationResult=" + event.mAuthenticationResult
1008                     + " mLatencyAuthenticationUiDisplayMillis="
1009                     + event.mLatencyAuthenticationUiDisplayMillis
1010                     + " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis
1011                     + " mAvailablePccCount=" + event.mAvailablePccCount
1012                     + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount
1013                     + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason
1014                     + " mDetectionPreference=" + event.mDetectionPreference
1015                     + " mFieldClassificationRequestId=" + event.mFieldClassificationRequestId
1016                     + " mAppPackageUid=" + mCallingAppUid
1017                     + " mIsCredentialRequest=" + event.mIsCredentialRequest
1018                     + " mWebviewRequestedCredential=" + event.mWebviewRequestedCredential
1019                     + " mFilteredFillabaleViewCount=" + event.mFilteredFillabaleViewCount
1020                     + " mViewFillableTotalCount=" + event.mViewFillableTotalCount
1021                     + " mViewFillFailureCount=" + event.mViewFillFailureCount
1022                     + " mFocusedId=" + event.mFocusedId
1023                     + " mViewFillSuccessCount=" + event.mViewFillSuccessCount
1024                     + " mViewFilledButUnexpectedCount=" + event.mViewFilledButUnexpectedCount
1025                     + " event.mSelectionTimestamp=" + event.mSelectionTimestamp
1026                     + " event.mAutofilledTimestampMs=" + event.mAutofilledTimestampMs
1027                     + " event.mFieldModifiedFirstTimestampMs="
1028                     + event.mFieldModifiedFirstTimestampMs
1029                     + " event.mFieldModifiedLastTimestampMs=" + event.mFieldModifiedLastTimestampMs
1030                     + " event.mSuggestionPresentedLastTimestampMs="
1031                     + event.mSuggestionPresentedLastTimestampMs
1032                     + " event.mFocusedVirtualAutofillId=" + event.mFocusedVirtualAutofillId
1033                     + " event.mFieldFirstLength=" + event.mFieldFirstLength
1034                     + " event.mFieldLastLength=" + event.mFieldLastLength
1035                     + " event.mViewFailedPriorToRefillCount=" + event.mViewFailedPriorToRefillCount
1036                     + " event.mViewFilledSuccessfullyOnRefillCount="
1037                     + event.mViewFilledSuccessfullyOnRefillCount
1038                     + " event.mViewFailedOnRefillCount=" + event.mViewFailedOnRefillCount
1039                     + " event.notExpiringResponseDuringAuthCount="
1040                     + event.mFixExpireResponseDuringAuthCount
1041                     + " event.notifyViewEnteredIgnoredDuringAuthCount="
1042                     + event.mNotifyViewEnteredIgnoredDuringAuthCount
1043                     + " event.fillDialogNotShownReason="
1044                     + event.mFillDialogNotShownReason
1045                     + " event.fillDialogReadyToShowMs="
1046                     + event.mFillDialogReadyToShowMs
1047                     + " event.imeAnimationFinishMs="
1048                     + event.mImeAnimationFinishMs);
1049         }
1050 
1051         // TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
1052         if (ignoreLogging) {
1053             Slog.w(TAG, "Empty dataset. Autofill ignoring log");
1054             mEventInternal = Optional.empty();
1055             return;
1056         }
1057         FrameworkStatsLog.write(
1058                 AUTOFILL_PRESENTATION_EVENT_REPORTED,
1059                 event.mRequestId,
1060                 mSessionId,
1061                 event.mNoPresentationReason,
1062                 event.mAvailableCount,
1063                 event.mCountShown,
1064                 event.mCountFilteredUserTyping,
1065                 event.mCountNotShownImePresentationNotDrawn,
1066                 event.mCountNotShownImeUserNotSeen,
1067                 event.mDisplayPresentationType,
1068                 event.mAutofillServiceUid,
1069                 event.mInlineSuggestionHostUid,
1070                 event.mIsRequestTriggered,
1071                 event.mFillRequestSentTimestampMs,
1072                 event.mFillResponseReceivedTimestampMs,
1073                 event.mSuggestionSentTimestampMs,
1074                 event.mSuggestionPresentedTimestampMs,
1075                 event.mSelectedDatasetId,
1076                 event.mDialogDismissed,
1077                 event.mNegativeCtaButtonClicked,
1078                 event.mPositiveCtaButtonClicked,
1079                 event.mAuthenticationType,
1080                 event.mAuthenticationResult,
1081                 event.mLatencyAuthenticationUiDisplayMillis,
1082                 event.mLatencyDatasetDisplayMillis,
1083                 event.mAvailablePccCount,
1084                 event.mAvailablePccOnlyCount,
1085                 event.mSelectedDatasetPickedReason,
1086                 event.mDetectionPreference,
1087                 event.mFieldClassificationRequestId,
1088                 mCallingAppUid,
1089                 event.mIsCredentialRequest,
1090                 event.mWebviewRequestedCredential,
1091                 event.mViewFillableTotalCount,
1092                 event.mViewFillFailureCount,
1093                 event.mFocusedId,
1094                 event.mViewFillSuccessCount,
1095                 event.mViewFilledButUnexpectedCount,
1096                 event.mSelectionTimestamp,
1097                 event.mAutofilledTimestampMs,
1098                 event.mFieldModifiedFirstTimestampMs,
1099                 event.mFieldModifiedLastTimestampMs,
1100                 event.mSuggestionPresentedLastTimestampMs,
1101                 event.mFocusedVirtualAutofillId,
1102                 event.mFieldFirstLength,
1103                 event.mFieldLastLength,
1104                 event.mFilteredFillabaleViewCount,
1105                 event.mViewFailedPriorToRefillCount,
1106                 event.mViewFilledSuccessfullyOnRefillCount,
1107                 event.mViewFailedOnRefillCount,
1108                 event.mFixExpireResponseDuringAuthCount,
1109                 event.mNotifyViewEnteredIgnoredDuringAuthCount,
1110                 event.mFillDialogNotShownReason,
1111                 event.mFillDialogReadyToShowMs,
1112                 event.mImeAnimationFinishMs);
1113         mEventInternal = Optional.empty();
1114     }
1115 
1116     static final class PresentationStatsEventInternal {
1117         int mRequestId;
1118         @NotShownReason int mNoPresentationReason = NOT_SHOWN_REASON_UNKNOWN;
1119         boolean mIsDatasetAvailable;
1120         int mAvailableCount;
1121         int mCountShown = 0;
1122         int mCountFilteredUserTyping;
1123         int mCountNotShownImePresentationNotDrawn;
1124         int mCountNotShownImeUserNotSeen;
1125         int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
1126         int mAutofillServiceUid = DEFAULT_VALUE_INT;
1127         int mInlineSuggestionHostUid = DEFAULT_VALUE_INT;
1128         boolean mIsRequestTriggered;
1129         int mFillRequestSentTimestampMs = DEFAULT_VALUE_INT;
1130         int mFillResponseReceivedTimestampMs = DEFAULT_VALUE_INT;
1131         int mSuggestionSentTimestampMs = DEFAULT_VALUE_INT;
1132         int mSuggestionPresentedTimestampMs = DEFAULT_VALUE_INT;
1133         int mSelectedDatasetId = DEFAULT_VALUE_INT;
1134         boolean mDialogDismissed = false;
1135         boolean mNegativeCtaButtonClicked = false;
1136         boolean mPositiveCtaButtonClicked = false;
1137         int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN;
1138         int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN;
1139         int mLatencyAuthenticationUiDisplayMillis = DEFAULT_VALUE_INT;
1140         int mLatencyDatasetDisplayMillis = DEFAULT_VALUE_INT;
1141         int mAvailablePccCount = DEFAULT_VALUE_INT;
1142         int mAvailablePccOnlyCount = DEFAULT_VALUE_INT;
1143         @DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN;
1144         @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN;
1145         int mFieldClassificationRequestId = DEFAULT_VALUE_INT;
1146         boolean mIsCredentialRequest = false;
1147         boolean mWebviewRequestedCredential = false;
1148         int mFilteredFillabaleViewCount = DEFAULT_VALUE_INT;
1149         int mViewFillableTotalCount = DEFAULT_VALUE_INT;
1150         int mViewFillFailureCount = DEFAULT_VALUE_INT;
1151         int mFocusedId = DEFAULT_VALUE_INT;
1152         int mSelectionTimestamp = DEFAULT_VALUE_INT;
1153         int mAutofilledTimestampMs = DEFAULT_VALUE_INT;
1154         int mFieldModifiedFirstTimestampMs = DEFAULT_VALUE_INT;
1155         int mFieldModifiedLastTimestampMs = DEFAULT_VALUE_INT;
1156         int mSuggestionPresentedLastTimestampMs = DEFAULT_VALUE_INT;
1157         int mFocusedVirtualAutofillId = DEFAULT_VALUE_INT;
1158         int mFieldFirstLength = DEFAULT_VALUE_INT;
1159         int mFieldLastLength = DEFAULT_VALUE_INT;
1160 
1161         // Default value for success count is set to 0 explicitly. Setting it to -1 for
1162         // uninitialized doesn't help much, as this would be non-zero only if callback is received.
1163         int mViewFillSuccessCount = 0;
1164         int mViewFilledButUnexpectedCount = 0;
1165         int mViewFailedPriorToRefillCount = 0;
1166         int mViewFailedOnRefillCount = 0;
1167         int mViewFilledSuccessfullyOnRefillCount = 0;
1168 
1169         int mFixExpireResponseDuringAuthCount = 0;
1170         int mNotifyViewEnteredIgnoredDuringAuthCount = 0;
1171 
1172         ArraySet<AutofillId> mAutofillIdsAttemptedAutofill;
1173         ArraySet<AutofillId> mFailedAutofillIds = new ArraySet<>();
1174         ArraySet<AutofillId> mAlreadyFilledAutofillIds = new ArraySet<>();
1175 
1176         // Following are not logged and used only for internal logic
1177         boolean shouldResetShownCount = false;
1178         boolean mHasRelayoutLog = false;
1179         @FillDialogNotShownReason int mFillDialogNotShownReason = FILL_DIALOG_NOT_SHOWN_REASON_UNKNOWN;
1180         int mFillDialogReadyToShowMs = DEFAULT_VALUE_INT;
1181         int mImeAnimationFinishMs = DEFAULT_VALUE_INT;
PresentationStatsEventInternal()1182         PresentationStatsEventInternal() {}
1183     }
1184 
getNoPresentationEventReason( @utofillManager.AutofillCommitReason int commitReason)1185     static int getNoPresentationEventReason(
1186             @AutofillManager.AutofillCommitReason int commitReason) {
1187         switch (commitReason) {
1188             case COMMIT_REASON_VIEW_COMMITTED:
1189                 return NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY;
1190             case COMMIT_REASON_ACTIVITY_FINISHED:
1191                 return NOT_SHOWN_REASON_ACTIVITY_FINISHED;
1192             case COMMIT_REASON_VIEW_CHANGED:
1193                 return NOT_SHOWN_REASON_VIEW_CHANGED;
1194             case COMMIT_REASON_VIEW_CLICKED:
1195                 // TODO(b/234185326): Add separate reason for view clicked.
1196             default:
1197                 return NOT_SHOWN_REASON_UNKNOWN;
1198         }
1199     }
1200 
getDisplayPresentationType(@iType int uiType)1201     private static int getDisplayPresentationType(@UiType int uiType) {
1202         switch (uiType) {
1203             case UI_TYPE_MENU:
1204                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
1205             case UI_TYPE_INLINE:
1206                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
1207             case UI_TYPE_DIALOG:
1208                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
1209             default:
1210                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
1211         }
1212     }
1213 }
1214