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__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
43 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
44 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED;
45 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS;
46 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
47 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
48 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
49 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
50 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE;
51 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
52 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC;
53 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY;
54 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER;
55 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY;
56 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC;
57 import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN;
58 import static com.android.server.autofill.Helper.sVerbose;
59 
60 import android.annotation.IntDef;
61 import android.annotation.Nullable;
62 import android.content.ComponentName;
63 import android.content.Context;
64 import android.content.pm.PackageManager;
65 import android.os.SystemClock;
66 import android.provider.Settings;
67 import android.service.autofill.Dataset;
68 import android.text.TextUtils;
69 import android.util.ArraySet;
70 import android.util.Slog;
71 import android.view.autofill.AutofillId;
72 import android.view.autofill.AutofillManager;
73 
74 import com.android.internal.util.FrameworkStatsLog;
75 
76 import java.lang.annotation.Retention;
77 import java.lang.annotation.RetentionPolicy;
78 import java.util.List;
79 import java.util.Optional;
80 
81 /** Helper class to track and log Autofill presentation stats. */
82 public final class PresentationStatsEventLogger {
83     private static final String TAG = "PresentationStatsEventLogger";
84 
85     /**
86      * Reasons why presentation was not shown. These are wrappers around
87      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}.
88      */
89     @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = {
90             NOT_SHOWN_REASON_ANY_SHOWN,
91             NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED,
92             NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE,
93             NOT_SHOWN_REASON_VIEW_CHANGED,
94             NOT_SHOWN_REASON_ACTIVITY_FINISHED,
95             NOT_SHOWN_REASON_REQUEST_TIMEOUT,
96             NOT_SHOWN_REASON_REQUEST_FAILED,
97             NOT_SHOWN_REASON_NO_FOCUS,
98             NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY,
99             NOT_SHOWN_REASON_UNKNOWN
100     })
101     @Retention(RetentionPolicy.SOURCE)
102     public @interface NotShownReason {}
103 
104     /**
105      * Reasons why presentation was not shown. These are wrappers around
106      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationType}.
107      */
108     @IntDef(prefix = {"AUTHENTICATION_TYPE"}, value = {
109             AUTHENTICATION_TYPE_UNKNOWN,
110             AUTHENTICATION_TYPE_DATASET_AUTHENTICATION,
111             AUTHENTICATION_TYPE_FULL_AUTHENTICATION
112     })
113     @Retention(RetentionPolicy.SOURCE)
114     public @interface AuthenticationType {
115     }
116 
117     /**
118      * Reasons why presentation was not shown. These are wrappers around
119      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationResult}.
120      */
121     @IntDef(prefix = {"AUTHENTICATION_RESULT"}, value = {
122             AUTHENTICATION_RESULT_UNKNOWN,
123             AUTHENTICATION_RESULT_SUCCESS,
124             AUTHENTICATION_RESULT_FAILURE
125     })
126     @Retention(RetentionPolicy.SOURCE)
127     public @interface AuthenticationResult {
128     }
129 
130     /**
131      * Reasons why the picked dataset was present. These are wrappers around
132      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DatasetPickedReason}.
133      * This enum is similar to {@link android.service.autofill.Dataset.DatasetEligibleReason}
134      */
135     @IntDef(prefix = {"PICK_REASON"}, value = {
136             PICK_REASON_UNKNOWN,
137             PICK_REASON_NO_PCC,
138             PICK_REASON_PROVIDER_DETECTION_ONLY,
139             PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC,
140             PICK_REASON_PCC_DETECTION_ONLY,
141             PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER,
142     })
143     @Retention(RetentionPolicy.SOURCE)
144     public @interface DatasetPickedReason {}
145 
146     /**
147      * The type of detection that was preferred. These are wrappers around
148      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DetectionPreference}.
149      */
150     @IntDef(prefix = {"DETECTION_PREFER"}, value = {
151             DETECTION_PREFER_UNKNOWN,
152             DETECTION_PREFER_AUTOFILL_PROVIDER,
153             DETECTION_PREFER_PCC
154     })
155     @Retention(RetentionPolicy.SOURCE)
156     public @interface DetectionPreference {
157     }
158 
159     public static final int NOT_SHOWN_REASON_ANY_SHOWN =
160             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
161     public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED =
162             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
163     public static final int NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE =
164             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE;
165     public static final int NOT_SHOWN_REASON_VIEW_CHANGED =
166             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
167     public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED =
168             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
169     public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT =
170             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
171     public static final int NOT_SHOWN_REASON_REQUEST_FAILED =
172             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED;
173     public static final int NOT_SHOWN_REASON_NO_FOCUS =
174             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS;
175     public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY =
176             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
177     public static final int NOT_SHOWN_REASON_UNKNOWN =
178             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
179 
180     public static final int AUTHENTICATION_TYPE_UNKNOWN =
181             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN;
182     public static final int AUTHENTICATION_TYPE_DATASET_AUTHENTICATION =
183             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION;
184     public static final int AUTHENTICATION_TYPE_FULL_AUTHENTICATION =
185             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION;
186 
187     public static final int AUTHENTICATION_RESULT_UNKNOWN =
188             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN;
189     public static final int AUTHENTICATION_RESULT_SUCCESS =
190             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS;
191     public static final int AUTHENTICATION_RESULT_FAILURE =
192             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE;
193 
194     public static final int PICK_REASON_UNKNOWN =
195             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN;
196     public static final int PICK_REASON_NO_PCC =
197             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC;
198      public static final int PICK_REASON_PROVIDER_DETECTION_ONLY =
199              AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY;
200     public static final int PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC =
201             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC;
202     public static final int PICK_REASON_PCC_DETECTION_ONLY =
203             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY;
204     public static final int PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER =
205             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER;
206 
207 
208     // Values for AutofillFillResponseReported.detection_preference
209     public static final int DETECTION_PREFER_UNKNOWN =
210             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
211     public static final int DETECTION_PREFER_AUTOFILL_PROVIDER =
212             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
213     public static final int DETECTION_PREFER_PCC =
214             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
215 
216     private static final int DEFAULT_VALUE_INT = -1;
217 
218     private final int mSessionId;
219     /**
220      * For app_package_uid.
221      */
222     private final int mCallingAppUid;
223     private Optional<PresentationStatsEventInternal> mEventInternal;
224     private final long mSessionStartTimestamp;
225 
PresentationStatsEventLogger(int sessionId, int callingAppUid, long timestamp)226     private PresentationStatsEventLogger(int sessionId, int callingAppUid, long timestamp) {
227         mSessionId = sessionId;
228         mCallingAppUid = callingAppUid;
229         mSessionStartTimestamp = timestamp;
230         mEventInternal = Optional.empty();
231     }
232 
233     /**
234      * Create PresentationStatsEventLogger, populated with sessionId and the callingAppUid
235      */
createPresentationLog( int sessionId, int callingAppUid, long timestamp)236     public static PresentationStatsEventLogger createPresentationLog(
237             int sessionId, int callingAppUid, long timestamp) {
238         return new PresentationStatsEventLogger(sessionId, callingAppUid, timestamp);
239     }
240 
startNewEvent()241     public void startNewEvent() {
242         if (mEventInternal.isPresent()) {
243             Slog.e(TAG, "Failed to start new event because already have active event.");
244             return;
245         }
246         mEventInternal = Optional.of(new PresentationStatsEventInternal());
247     }
248 
249     /**
250      * Set request_id
251      */
maybeSetRequestId(int requestId)252     public void maybeSetRequestId(int requestId) {
253         mEventInternal.ifPresent(event -> event.mRequestId = requestId);
254     }
255 
256     /**
257      * Set is_credential_request
258      */
maybeSetIsCredentialRequest(boolean isCredentialRequest)259     public void maybeSetIsCredentialRequest(boolean isCredentialRequest) {
260         mEventInternal.ifPresent(event -> event.mIsCredentialRequest = isCredentialRequest);
261     }
262 
263     /**
264      * Set webview_requested_credential
265      */
maybeSetWebviewRequestedCredential(boolean webviewRequestedCredential)266     public void maybeSetWebviewRequestedCredential(boolean webviewRequestedCredential) {
267         mEventInternal.ifPresent(event ->
268                 event.mWebviewRequestedCredential = webviewRequestedCredential);
269     }
270 
maybeSetNoPresentationEventReason(@otShownReason int reason)271     public void maybeSetNoPresentationEventReason(@NotShownReason int reason) {
272         mEventInternal.ifPresent(event -> {
273             if (event.mCountShown == 0) {
274                 event.mNoPresentationReason = reason;
275             }
276         });
277     }
278 
maybeSetNoPresentationEventReasonIfNoReasonExists(@otShownReason int reason)279     public void maybeSetNoPresentationEventReasonIfNoReasonExists(@NotShownReason int reason) {
280         mEventInternal.ifPresent(event -> {
281             if (event.mCountShown == 0 && event.mNoPresentationReason == NOT_SHOWN_REASON_UNKNOWN) {
282                 event.mNoPresentationReason = reason;
283             }
284         });
285     }
286 
maybeSetAvailableCount(@ullable List<Dataset> datasetList, AutofillId currentViewId)287     public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList,
288             AutofillId currentViewId) {
289         mEventInternal.ifPresent(event -> {
290             CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId);
291             event.mAvailableCount = container.mAvailableCount;
292             event.mAvailablePccCount = container.mAvailablePccCount;
293             event.mAvailablePccOnlyCount = container.mAvailablePccOnlyCount;
294             event.mIsDatasetAvailable = container.mAvailableCount > 0;
295         });
296     }
297 
298     /**
299      * Called for inline suggestions - inflated one at
300      * a time. If InlineSuggestions were filtered,
301      * reset the count be incrementing
302      */
maybeIncrementCountShown()303     public void maybeIncrementCountShown() {
304         mEventInternal.ifPresent(event -> {
305             if (event.shouldResetShownCount) {
306                 event.shouldResetShownCount = false;
307                 event.mCountShown = 0;
308             }
309 
310             if (event.mCountShown == 0) {
311                 // The first time suggestions are rendered
312                 // set time stamp
313                 maybeSetSuggestionPresentedTimestampMs();
314             }
315 
316             event.mCountShown += 1;
317         });
318     }
319 
320     /**
321      * Call this when UI is hidden. This will set a flag to reset count for inline. We do this
322      * instead of resetting right away in case there are 0 inline presentations after.
323      */
markShownCountAsResettable()324     public void markShownCountAsResettable() {
325         mEventInternal.ifPresent(event -> {
326             event.shouldResetShownCount = true;
327         });
328     }
329 
maybeSetCountShown(@ullable List<Dataset> datasetList, AutofillId currentViewId)330     public void maybeSetCountShown(@Nullable List<Dataset> datasetList,
331             AutofillId currentViewId) {
332         mEventInternal.ifPresent(event -> {
333             CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId);
334             event.mCountShown = container.mAvailableCount;
335             if (container.mAvailableCount > 0) {
336                 event.mNoPresentationReason = NOT_SHOWN_REASON_ANY_SHOWN;
337             }
338         });
339     }
340 
maybeSetCountShown(int datasets)341     public void maybeSetCountShown(int datasets) {
342         mEventInternal.ifPresent(
343                 event -> {
344                     event.mCountShown = datasets;
345                 });
346     }
347 
getDatasetCountForAutofillId(@ullable List<Dataset> datasetList, AutofillId currentViewId)348     private static CountContainer getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList,
349             AutofillId currentViewId) {
350 
351         CountContainer container = new CountContainer();
352         if (datasetList != null) {
353             for (int i = 0; i < datasetList.size(); i++) {
354                 Dataset data = datasetList.get(i);
355                 if (data != null && data.getFieldIds() != null
356                         && data.getFieldIds().contains(currentViewId)) {
357                     container.mAvailableCount += 1;
358                     if (data.getEligibleReason() == PICK_REASON_PCC_DETECTION_ONLY) {
359                         container.mAvailablePccOnlyCount++;
360                         container.mAvailablePccCount++;
361                     } else if (data.getEligibleReason()
362                             == PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER) {
363                         container.mAvailablePccCount++;
364                     }
365                 }
366             }
367         }
368         return container;
369     }
370 
371     private static class CountContainer{
372         int mAvailableCount = 0;
373         int mAvailablePccCount = 0;
374         int mAvailablePccOnlyCount = 0;
375 
CountContainer()376         CountContainer() {}
377 
CountContainer(int availableCount, int availablePccCount, int availablePccOnlyCount)378         CountContainer(int availableCount, int availablePccCount,
379                 int availablePccOnlyCount) {
380             mAvailableCount = availableCount;
381             mAvailablePccCount = availablePccCount;
382             mAvailablePccOnlyCount = availablePccOnlyCount;
383         }
384     }
385 
maybeSetCountFilteredUserTyping(int countFilteredUserTyping)386     public void maybeSetCountFilteredUserTyping(int countFilteredUserTyping) {
387         mEventInternal.ifPresent(event -> {
388             event.mCountFilteredUserTyping = countFilteredUserTyping;
389         });
390     }
391 
maybeSetCountNotShownImePresentationNotDrawn( int countNotShownImePresentationNotDrawn)392     public void maybeSetCountNotShownImePresentationNotDrawn(
393             int countNotShownImePresentationNotDrawn) {
394         mEventInternal.ifPresent(event -> {
395             event.mCountNotShownImePresentationNotDrawn = countNotShownImePresentationNotDrawn;
396         });
397     }
398 
maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen)399     public void maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen) {
400         mEventInternal.ifPresent(event -> {
401             event.mCountNotShownImeUserNotSeen = countNotShownImeUserNotSeen;
402         });
403     }
404 
maybeSetDisplayPresentationType(@iType int uiType)405     public void maybeSetDisplayPresentationType(@UiType int uiType) {
406         mEventInternal.ifPresent(event -> {
407             event.mDisplayPresentationType = getDisplayPresentationType(uiType);
408         });
409     }
410 
maybeSetFillRequestSentTimestampMs(int timestamp)411     public void maybeSetFillRequestSentTimestampMs(int timestamp) {
412         mEventInternal.ifPresent(event -> {
413             event.mFillRequestSentTimestampMs = timestamp;
414         });
415     }
416 
maybeSetFillRequestSentTimestampMs()417     public void maybeSetFillRequestSentTimestampMs() {
418         maybeSetFillRequestSentTimestampMs(getElapsedTime());
419     }
420 
maybeSetFillResponseReceivedTimestampMs(int timestamp)421     public void maybeSetFillResponseReceivedTimestampMs(int timestamp) {
422         mEventInternal.ifPresent(event -> {
423             event.mFillResponseReceivedTimestampMs = timestamp;
424         });
425     }
426 
maybeSetFillResponseReceivedTimestampMs()427     public void maybeSetFillResponseReceivedTimestampMs() {
428         maybeSetFillResponseReceivedTimestampMs(getElapsedTime());
429     }
430 
maybeSetSuggestionSentTimestampMs(int timestamp)431     public void maybeSetSuggestionSentTimestampMs(int timestamp) {
432         mEventInternal.ifPresent(event -> {
433             event.mSuggestionSentTimestampMs = timestamp;
434         });
435     }
436 
maybeSetSuggestionSentTimestampMs()437     public void maybeSetSuggestionSentTimestampMs() {
438         maybeSetSuggestionSentTimestampMs(getElapsedTime());
439     }
440 
maybeSetSuggestionPresentedTimestampMs(int timestamp)441     public void maybeSetSuggestionPresentedTimestampMs(int timestamp) {
442         mEventInternal.ifPresent(event -> {
443             // mSuggestionPresentedTimestampMs only tracks the first suggested timestamp.
444             if (event.mSuggestionPresentedTimestampMs == DEFAULT_VALUE_INT) {
445                 event.mSuggestionPresentedTimestampMs = timestamp;
446             }
447 
448             event.mSuggestionPresentedLastTimestampMs = timestamp;
449         });
450     }
451 
maybeSetSuggestionPresentedTimestampMs()452     public void maybeSetSuggestionPresentedTimestampMs() {
453         maybeSetSuggestionPresentedTimestampMs(getElapsedTime());
454     }
455 
maybeSetSelectedDatasetId(int selectedDatasetId)456     public void maybeSetSelectedDatasetId(int selectedDatasetId) {
457         mEventInternal.ifPresent(event -> {
458             event.mSelectedDatasetId = selectedDatasetId;
459         });
460         setPresentationSelectedTimestamp();
461     }
462 
maybeSetDialogDismissed(boolean dialogDismissed)463     public void maybeSetDialogDismissed(boolean dialogDismissed) {
464         mEventInternal.ifPresent(event -> {
465             event.mDialogDismissed = dialogDismissed;
466         });
467     }
468 
maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked)469     public void maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked) {
470         mEventInternal.ifPresent(event -> {
471             event.mNegativeCtaButtonClicked = negativeCtaButtonClicked;
472         });
473     }
474 
maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked)475     public void maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked) {
476         mEventInternal.ifPresent(event -> {
477             event.mPositiveCtaButtonClicked = positiveCtaButtonClicked;
478         });
479     }
480 
maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId)481     public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) {
482         mEventInternal.ifPresent(event -> {
483             event.mDisplayPresentationType =
484                     AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
485             String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
486                     Settings.Secure.DEFAULT_INPUT_METHOD, userId);
487             if (TextUtils.isEmpty(imeString)) {
488                 Slog.w(TAG, "No default IME found");
489                 return;
490             }
491             ComponentName imeComponent = ComponentName.unflattenFromString(imeString);
492             if (imeComponent == null) {
493                 Slog.w(TAG, "No default IME found");
494                 return;
495             }
496             int imeUid;
497             String packageName = imeComponent.getPackageName();
498             try {
499                 imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName,
500                         PackageManager.ApplicationInfoFlags.of(0), userId).uid;
501             } catch (PackageManager.NameNotFoundException e) {
502                 Slog.w(TAG, "Couldn't find packageName: " + packageName);
503                 return;
504             }
505             event.mInlineSuggestionHostUid = imeUid;
506         });
507     }
508 
maybeSetAutofillServiceUid(int uid)509     public void maybeSetAutofillServiceUid(int uid) {
510         mEventInternal.ifPresent(event -> {
511             event.mAutofillServiceUid = uid;
512         });
513     }
514 
maybeSetIsNewRequest(boolean isRequestTriggered)515     public void maybeSetIsNewRequest(boolean isRequestTriggered) {
516         mEventInternal.ifPresent(event -> {
517             event.mIsRequestTriggered = isRequestTriggered;
518         });
519     }
520 
521     /**
522      * Set authentication_type as long as mEventInternal presents.
523      */
maybeSetAuthenticationType(@uthenticationType int val)524     public void maybeSetAuthenticationType(@AuthenticationType int val) {
525         mEventInternal.ifPresent(event -> {
526             event.mAuthenticationType = val;
527         });
528     }
529 
530     /**
531      * Set authentication_result as long as mEventInternal presents.
532      */
maybeSetAuthenticationResult(@uthenticationResult int val)533     public void maybeSetAuthenticationResult(@AuthenticationResult int val) {
534         mEventInternal.ifPresent(event -> {
535             event.mAuthenticationResult = val;
536         });
537     }
538 
539     /**
540      * Set latency_authentication_ui_display_millis as long as mEventInternal presents.
541      */
maybeSetLatencyAuthenticationUiDisplayMillis(int val)542     public void maybeSetLatencyAuthenticationUiDisplayMillis(int val) {
543         mEventInternal.ifPresent(event -> {
544             event.mLatencyAuthenticationUiDisplayMillis = val;
545         });
546     }
547 
548     /** Set latency_authentication_ui_display_millis as long as mEventInternal presents. */
maybeSetLatencyAuthenticationUiDisplayMillis()549     public void maybeSetLatencyAuthenticationUiDisplayMillis() {
550         maybeSetLatencyAuthenticationUiDisplayMillis(getElapsedTime());
551     }
552 
553     /**
554      * Set latency_dataset_display_millis as long as mEventInternal presents.
555      */
maybeSetLatencyDatasetDisplayMillis(int val)556     public void maybeSetLatencyDatasetDisplayMillis(int val) {
557         mEventInternal.ifPresent(event -> {
558             event.mLatencyDatasetDisplayMillis = val;
559         });
560     }
561 
562     /** Set latency_dataset_display_millis as long as mEventInternal presents. */
maybeSetLatencyDatasetDisplayMillis()563     public void maybeSetLatencyDatasetDisplayMillis() {
564         maybeSetLatencyDatasetDisplayMillis(getElapsedTime());
565     }
566 
567     /**
568      * Set available_pcc_count.
569      */
maybeSetAvailablePccCount(int val)570     public void maybeSetAvailablePccCount(int val) {
571         mEventInternal.ifPresent(event -> {
572             event.mAvailablePccCount = val;
573         });
574     }
575 
576     /**
577      * Set available_pcc_only_count.
578      */
maybeSetAvailablePccOnlyCount(int val)579     public void maybeSetAvailablePccOnlyCount(int val) {
580         mEventInternal.ifPresent(event -> {
581             event.mAvailablePccOnlyCount = val;
582         });
583     }
584 
585     /**
586      * Set selected_dataset_picked_reason.
587      */
maybeSetSelectedDatasetPickReason(@ataset.DatasetEligibleReason int val)588     public void maybeSetSelectedDatasetPickReason(@Dataset.DatasetEligibleReason int val) {
589         mEventInternal.ifPresent(event -> {
590             event.mSelectedDatasetPickedReason = convertDatasetPickReason(val);
591         });
592     }
593 
594     /**
595      * Set detection_pref
596      */
maybeSetDetectionPreference(@etectionPreference int detectionPreference)597     public void maybeSetDetectionPreference(@DetectionPreference int detectionPreference) {
598         mEventInternal.ifPresent(event -> {
599             event.mDetectionPreference = detectionPreference;
600         });
601     }
602 
603     /**
604      * Set various timestamps whenever the ViewState is modified
605      *
606      * <p>If the ViewState contains ViewState.STATE_AUTOFILLED, sets field_autofilled_timestamp_ms
607      * else, set field_first_modified_timestamp_ms (if unset) and field_last_modified_timestamp_ms
608      */
onFieldTextUpdated(ViewState state, int length)609     public void onFieldTextUpdated(ViewState state, int length) {
610         mEventInternal.ifPresent(event -> {
611                     int timestamp = getElapsedTime();
612                     // Focused id should be set before this is called
613                     if (state == null || state.id == null || state.id.getViewId() != event.mFocusedId) {
614                         // if these don't match, the currently field different than before
615                         Slog.w(
616                                 TAG,
617                                 "Bad view state for: " + event.mFocusedId);
618                         return;
619                     }
620 
621                     // Text changed because filling into form, just log Autofill timestamp
622                     if ((state.getState() & ViewState.STATE_AUTOFILLED) != 0) {
623                         event.mAutofilledTimestampMs = timestamp;
624                         return;
625                     }
626 
627                     // Set length variables
628                     if (event.mFieldFirstLength == DEFAULT_VALUE_INT) {
629                         event.mFieldFirstLength = length;
630                     }
631                     event.mFieldLastLength = length;
632 
633                     // Set timestamp variables
634                     if (event.mFieldModifiedFirstTimestampMs == DEFAULT_VALUE_INT) {
635                         event.mFieldModifiedFirstTimestampMs = timestamp;
636                     }
637                     event.mFieldModifiedLastTimestampMs = timestamp;
638         });
639     }
640 
setPresentationSelectedTimestamp()641     public void setPresentationSelectedTimestamp() {
642         mEventInternal.ifPresent(event -> {
643             event.mSelectionTimestamp = getElapsedTime();
644         });
645     }
646 
647     /**
648      * Returns timestamp (relative to mSessionStartTimestamp)
649      */
getElapsedTime()650     private int getElapsedTime() {
651         return (int)(SystemClock.elapsedRealtime() - mSessionStartTimestamp);
652     }
653 
654 
convertDatasetPickReason(@ataset.DatasetEligibleReason int val)655     private int convertDatasetPickReason(@Dataset.DatasetEligibleReason int val) {
656         switch (val) {
657             case 0:
658             case 1:
659             case 2:
660             case 3:
661             case 4:
662             case 5:
663                 return val;
664         }
665         return PICK_REASON_UNKNOWN;
666     }
667 
668     /**
669      * Set field_classification_request_id as long as mEventInternal presents.
670      */
maybeSetFieldClassificationRequestId(int requestId)671     public void maybeSetFieldClassificationRequestId(int requestId) {
672         mEventInternal.ifPresent(event -> {
673             event.mFieldClassificationRequestId = requestId;
674         });
675     }
676 
677     /**
678      * Set views_fillable_total_count as long as mEventInternal presents.
679      */
maybeSetViewFillablesAndCount(List<AutofillId> autofillIds)680     public void maybeSetViewFillablesAndCount(List<AutofillId> autofillIds) {
681         mEventInternal.ifPresent(event -> {
682             event.mAutofillIdsAttemptedAutofill = new ArraySet<>(autofillIds);
683             event.mViewFillableTotalCount = event.mAutofillIdsAttemptedAutofill.size();
684         });
685     }
686 
687     /**
688      * Set views_filled_failure_count using failure count as long as mEventInternal
689      * presents.
690      */
maybeSetViewFillFailureCounts(int failureCount)691     public void maybeSetViewFillFailureCounts(int failureCount) {
692         mEventInternal.ifPresent(event -> {
693             event.mViewFillFailureCount = failureCount;
694         });
695     }
696 
697     /** Sets focused_autofill_id using view id */
maybeSetFocusedId(AutofillId id)698     public void maybeSetFocusedId(AutofillId id) {
699         mEventInternal.ifPresent(
700                 event -> {
701                     event.mFocusedId = id.getViewId();
702                     if (id.isVirtualInt()) {
703                         event.mFocusedVirtualAutofillId =
704                                 id.getVirtualChildIntId() % 100;
705                     }
706                 });
707     }
708 
709     /**
710      * Set views_filled_failure_count using failure count as long as mEventInternal
711      * presents.
712      */
maybeAddSuccessId(AutofillId autofillId)713     public void maybeAddSuccessId(AutofillId autofillId) {
714         mEventInternal.ifPresent(event -> {
715             ArraySet<AutofillId> autofillIds = event.mAutofillIdsAttemptedAutofill;
716             if (autofillIds == null) {
717                 Slog.w(TAG, "Attempted autofill ids is null, but received autofillId:" + autofillId
718                         + " successfully filled");
719                 event.mViewFilledButUnexpectedCount++;
720             } else if (autofillIds.contains(autofillId)) {
721                 if (sVerbose) {
722                     Slog.v(TAG, "Logging autofill for id:" + autofillId);
723                 }
724                 event.mViewFillSuccessCount++;
725                 autofillIds.remove(autofillId);
726                 event.mAlreadyFilledAutofillIds.add(autofillId);
727             } else if (event.mAlreadyFilledAutofillIds.contains(autofillId)) {
728                 if (sVerbose) {
729                     Slog.v(TAG, "Successfully filled autofillId:" + autofillId
730                             + " already processed ");
731                 }
732             } else {
733                 Slog.w(TAG, "Successfully filled autofillId:" + autofillId
734                         + " not found in list of attempted autofill ids: " + autofillIds);
735                 event.mViewFilledButUnexpectedCount++;
736             }
737         });
738     }
739 
logAndEndEvent()740     public void logAndEndEvent() {
741         if (!mEventInternal.isPresent()) {
742             Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same "
743                     + "event");
744             return;
745         }
746         PresentationStatsEventInternal event = mEventInternal.get();
747         if (sVerbose) {
748             Slog.v(TAG, "Log AutofillPresentationEventReported:"
749                     + " requestId=" + event.mRequestId
750                     + " sessionId=" + mSessionId
751                     + " mNoPresentationEventReason=" + event.mNoPresentationReason
752                     + " mAvailableCount=" + event.mAvailableCount
753                     + " mCountShown=" + event.mCountShown
754                     + " mCountFilteredUserTyping=" + event.mCountFilteredUserTyping
755                     + " mCountNotShownImePresentationNotDrawn="
756                     + event.mCountNotShownImePresentationNotDrawn
757                     + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen
758                     + " mDisplayPresentationType=" + event.mDisplayPresentationType
759                     + " mAutofillServiceUid=" + event.mAutofillServiceUid
760                     + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid
761                     + " mIsRequestTriggered=" + event.mIsRequestTriggered
762                     + " mFillRequestSentTimestampMs=" + event.mFillRequestSentTimestampMs
763                     + " mFillResponseReceivedTimestampMs=" + event.mFillResponseReceivedTimestampMs
764                     + " mSuggestionSentTimestampMs=" + event.mSuggestionSentTimestampMs
765                     + " mSuggestionPresentedTimestampMs=" + event.mSuggestionPresentedTimestampMs
766                     + " mSelectedDatasetId=" + event.mSelectedDatasetId
767                     + " mDialogDismissed=" + event.mDialogDismissed
768                     + " mNegativeCtaButtonClicked=" + event.mNegativeCtaButtonClicked
769                     + " mPositiveCtaButtonClicked=" + event.mPositiveCtaButtonClicked
770                     + " mAuthenticationType=" + event.mAuthenticationType
771                     + " mAuthenticationResult=" + event.mAuthenticationResult
772                     + " mLatencyAuthenticationUiDisplayMillis="
773                     + event.mLatencyAuthenticationUiDisplayMillis
774                     + " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis
775                     + " mAvailablePccCount=" + event.mAvailablePccCount
776                     + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount
777                     + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason
778                     + " mDetectionPreference=" + event.mDetectionPreference
779                     + " mFieldClassificationRequestId=" + event.mFieldClassificationRequestId
780                     + " mAppPackageUid=" + mCallingAppUid
781                     + " mIsCredentialRequest=" + event.mIsCredentialRequest
782                     + " mWebviewRequestedCredential=" + event.mWebviewRequestedCredential
783                     + " mViewFillableTotalCount=" + event.mViewFillableTotalCount
784                     + " mViewFillFailureCount=" + event.mViewFillFailureCount
785                     + " mFocusedId=" + event.mFocusedId
786                     + " mViewFillSuccessCount=" + event.mViewFillSuccessCount
787                     + " mViewFilledButUnexpectedCount=" + event.mViewFilledButUnexpectedCount
788                     + " event.mSelectionTimestamp=" + event.mSelectionTimestamp
789                     + " event.mAutofilledTimestampMs=" + event.mAutofilledTimestampMs
790                     + " event.mFieldModifiedFirstTimestampMs="
791                     + event.mFieldModifiedFirstTimestampMs
792                     + " event.mFieldModifiedLastTimestampMs=" + event.mFieldModifiedLastTimestampMs
793                     + " event.mSuggestionPresentedLastTimestampMs="
794                     + event.mSuggestionPresentedLastTimestampMs
795                     + " event.mFocusedVirtualAutofillId=" + event.mFocusedVirtualAutofillId
796                     + " event.mFieldFirstLength=" + event.mFieldFirstLength
797                     + " event.mFieldLastLength=" + event.mFieldLastLength);
798         }
799 
800         // TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
801         if (!event.mIsDatasetAvailable) {
802             mEventInternal = Optional.empty();
803             return;
804         }
805         FrameworkStatsLog.write(
806                 AUTOFILL_PRESENTATION_EVENT_REPORTED,
807                 event.mRequestId,
808                 mSessionId,
809                 event.mNoPresentationReason,
810                 event.mAvailableCount,
811                 event.mCountShown,
812                 event.mCountFilteredUserTyping,
813                 event.mCountNotShownImePresentationNotDrawn,
814                 event.mCountNotShownImeUserNotSeen,
815                 event.mDisplayPresentationType,
816                 event.mAutofillServiceUid,
817                 event.mInlineSuggestionHostUid,
818                 event.mIsRequestTriggered,
819                 event.mFillRequestSentTimestampMs,
820                 event.mFillResponseReceivedTimestampMs,
821                 event.mSuggestionSentTimestampMs,
822                 event.mSuggestionPresentedTimestampMs,
823                 event.mSelectedDatasetId,
824                 event.mDialogDismissed,
825                 event.mNegativeCtaButtonClicked,
826                 event.mPositiveCtaButtonClicked,
827                 event.mAuthenticationType,
828                 event.mAuthenticationResult,
829                 event.mLatencyAuthenticationUiDisplayMillis,
830                 event.mLatencyDatasetDisplayMillis,
831                 event.mAvailablePccCount,
832                 event.mAvailablePccOnlyCount,
833                 event.mSelectedDatasetPickedReason,
834                 event.mDetectionPreference,
835                 event.mFieldClassificationRequestId,
836                 mCallingAppUid,
837                 event.mIsCredentialRequest,
838                 event.mWebviewRequestedCredential,
839                 event.mViewFillableTotalCount,
840                 event.mViewFillFailureCount,
841                 event.mFocusedId,
842                 event.mViewFillSuccessCount,
843                 event.mViewFilledButUnexpectedCount,
844                 event.mSelectionTimestamp,
845                 event.mAutofilledTimestampMs,
846                 event.mFieldModifiedFirstTimestampMs,
847                 event.mFieldModifiedLastTimestampMs,
848                 event.mSuggestionPresentedLastTimestampMs,
849                 event.mFocusedVirtualAutofillId,
850                 event.mFieldFirstLength,
851                 event.mFieldLastLength);
852         mEventInternal = Optional.empty();
853     }
854 
855     private static final class PresentationStatsEventInternal {
856         int mRequestId;
857         @NotShownReason int mNoPresentationReason = NOT_SHOWN_REASON_UNKNOWN;
858         boolean mIsDatasetAvailable;
859         int mAvailableCount;
860         int mCountShown = 0;
861         int mCountFilteredUserTyping;
862         int mCountNotShownImePresentationNotDrawn;
863         int mCountNotShownImeUserNotSeen;
864         int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
865         int mAutofillServiceUid = DEFAULT_VALUE_INT;
866         int mInlineSuggestionHostUid = DEFAULT_VALUE_INT;
867         boolean mIsRequestTriggered;
868         int mFillRequestSentTimestampMs = DEFAULT_VALUE_INT;
869         int mFillResponseReceivedTimestampMs = DEFAULT_VALUE_INT;
870         int mSuggestionSentTimestampMs = DEFAULT_VALUE_INT;
871         int mSuggestionPresentedTimestampMs = DEFAULT_VALUE_INT;
872         int mSelectedDatasetId = DEFAULT_VALUE_INT;
873         boolean mDialogDismissed = false;
874         boolean mNegativeCtaButtonClicked = false;
875         boolean mPositiveCtaButtonClicked = false;
876         int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN;
877         int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN;
878         int mLatencyAuthenticationUiDisplayMillis = DEFAULT_VALUE_INT;
879         int mLatencyDatasetDisplayMillis = DEFAULT_VALUE_INT;
880         int mAvailablePccCount = DEFAULT_VALUE_INT;
881         int mAvailablePccOnlyCount = DEFAULT_VALUE_INT;
882         @DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN;
883         @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN;
884         int mFieldClassificationRequestId = DEFAULT_VALUE_INT;
885         boolean mIsCredentialRequest = false;
886         boolean mWebviewRequestedCredential = false;
887         int mViewFillableTotalCount = DEFAULT_VALUE_INT;
888         int mViewFillFailureCount = DEFAULT_VALUE_INT;
889         int mFocusedId = DEFAULT_VALUE_INT;
890         int mSelectionTimestamp = DEFAULT_VALUE_INT;
891         int mAutofilledTimestampMs = DEFAULT_VALUE_INT;
892         int mFieldModifiedFirstTimestampMs = DEFAULT_VALUE_INT;
893         int mFieldModifiedLastTimestampMs = DEFAULT_VALUE_INT;
894         int mSuggestionPresentedLastTimestampMs = DEFAULT_VALUE_INT;
895         int mFocusedVirtualAutofillId = DEFAULT_VALUE_INT;
896         int mFieldFirstLength = DEFAULT_VALUE_INT;
897         int mFieldLastLength = DEFAULT_VALUE_INT;
898 
899         // Default value for success count is set to 0 explicitly. Setting it to -1 for
900         // uninitialized doesn't help much, as this would be non-zero only if callback is received.
901         int mViewFillSuccessCount = 0;
902         int mViewFilledButUnexpectedCount = 0;
903 
904         ArraySet<AutofillId> mAutofillIdsAttemptedAutofill;
905         ArraySet<AutofillId> mAlreadyFilledAutofillIds = new ArraySet<>();
906 
907         // Not logged - used for internal logic
908         boolean shouldResetShownCount = false;
PresentationStatsEventInternal()909         PresentationStatsEventInternal() {}
910     }
911 
getNoPresentationEventReason( @utofillManager.AutofillCommitReason int commitReason)912     static int getNoPresentationEventReason(
913             @AutofillManager.AutofillCommitReason int commitReason) {
914         switch (commitReason) {
915             case COMMIT_REASON_VIEW_COMMITTED:
916                 return NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY;
917             case COMMIT_REASON_ACTIVITY_FINISHED:
918                 return NOT_SHOWN_REASON_ACTIVITY_FINISHED;
919             case COMMIT_REASON_VIEW_CHANGED:
920                 return NOT_SHOWN_REASON_VIEW_CHANGED;
921             case COMMIT_REASON_VIEW_CLICKED:
922                 // TODO(b/234185326): Add separate reason for view clicked.
923             default:
924                 return NOT_SHOWN_REASON_UNKNOWN;
925         }
926     }
927 
getDisplayPresentationType(@iType int uiType)928     private static int getDisplayPresentationType(@UiType int uiType) {
929         switch (uiType) {
930             case UI_TYPE_MENU:
931                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
932             case UI_TYPE_INLINE:
933                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
934             case UI_TYPE_DIALOG:
935                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
936             default:
937                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
938         }
939     }
940 }
941