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.provider.Settings;
66 import android.service.autofill.Dataset;
67 import android.text.TextUtils;
68 import android.util.Slog;
69 import android.view.autofill.AutofillId;
70 import android.view.autofill.AutofillManager;
71 
72 import com.android.internal.util.FrameworkStatsLog;
73 
74 import java.lang.annotation.Retention;
75 import java.lang.annotation.RetentionPolicy;
76 import java.util.List;
77 import java.util.Optional;
78 
79 /** Helper class to track and log Autofill presentation stats. */
80 public final class PresentationStatsEventLogger {
81     private static final String TAG = "PresentationStatsEventLogger";
82 
83     /**
84      * Reasons why presentation was not shown. These are wrappers around
85      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}.
86      */
87     @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = {
88             NOT_SHOWN_REASON_ANY_SHOWN,
89             NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED,
90             NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE,
91             NOT_SHOWN_REASON_VIEW_CHANGED,
92             NOT_SHOWN_REASON_ACTIVITY_FINISHED,
93             NOT_SHOWN_REASON_REQUEST_TIMEOUT,
94             NOT_SHOWN_REASON_REQUEST_FAILED,
95             NOT_SHOWN_REASON_NO_FOCUS,
96             NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY,
97             NOT_SHOWN_REASON_UNKNOWN
98     })
99     @Retention(RetentionPolicy.SOURCE)
100     public @interface NotShownReason {}
101 
102     /**
103      * Reasons why presentation was not shown. These are wrappers around
104      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationType}.
105      */
106     @IntDef(prefix = {"AUTHENTICATION_TYPE"}, value = {
107             AUTHENTICATION_TYPE_UNKNOWN,
108             AUTHENTICATION_TYPE_DATASET_AUTHENTICATION,
109             AUTHENTICATION_TYPE_FULL_AUTHENTICATION
110     })
111     @Retention(RetentionPolicy.SOURCE)
112     public @interface AuthenticationType {
113     }
114 
115     /**
116      * Reasons why presentation was not shown. These are wrappers around
117      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.AuthenticationResult}.
118      */
119     @IntDef(prefix = {"AUTHENTICATION_RESULT"}, value = {
120             AUTHENTICATION_RESULT_UNKNOWN,
121             AUTHENTICATION_RESULT_SUCCESS,
122             AUTHENTICATION_RESULT_FAILURE
123     })
124     @Retention(RetentionPolicy.SOURCE)
125     public @interface AuthenticationResult {
126     }
127 
128     /**
129      * Reasons why the picked dataset was present. These are wrappers around
130      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DatasetPickedReason}.
131      * This enum is similar to {@link android.service.autofill.Dataset.DatasetEligibleReason}
132      */
133     @IntDef(prefix = {"PICK_REASON"}, value = {
134             PICK_REASON_UNKNOWN,
135             PICK_REASON_NO_PCC,
136             PICK_REASON_PROVIDER_DETECTION_ONLY,
137             PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC,
138             PICK_REASON_PCC_DETECTION_ONLY,
139             PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER,
140     })
141     @Retention(RetentionPolicy.SOURCE)
142     public @interface DatasetPickedReason {}
143 
144     /**
145      * The type of detection that was preferred. These are wrappers around
146      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DetectionPreference}.
147      */
148     @IntDef(prefix = {"DETECTION_PREFER"}, value = {
149             DETECTION_PREFER_UNKNOWN,
150             DETECTION_PREFER_AUTOFILL_PROVIDER,
151             DETECTION_PREFER_PCC
152     })
153     @Retention(RetentionPolicy.SOURCE)
154     public @interface DetectionPreference {
155     }
156 
157     public static final int NOT_SHOWN_REASON_ANY_SHOWN =
158             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
159     public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED =
160             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
161     public static final int NOT_SHOWN_REASON_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE =
162             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUSED_BEFORE_FILL_DIALOG_RESPONSE;
163     public static final int NOT_SHOWN_REASON_VIEW_CHANGED =
164             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
165     public static final int NOT_SHOWN_REASON_ACTIVITY_FINISHED =
166             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_ACTIVITY_FINISHED;
167     public static final int NOT_SHOWN_REASON_REQUEST_TIMEOUT =
168             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_REQUEST_TIMEOUT;
169     public static final int NOT_SHOWN_REASON_REQUEST_FAILED =
170             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_FILL_REQUEST_FAILED;
171     public static final int NOT_SHOWN_REASON_NO_FOCUS =
172             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_NO_FOCUS;
173     public static final int NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY =
174             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_SESSION_COMMITTED_PREMATURELY;
175     public static final int NOT_SHOWN_REASON_UNKNOWN =
176             AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_UNKNOWN_REASON;
177 
178     public static final int AUTHENTICATION_TYPE_UNKNOWN =
179             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN;
180     public static final int AUTHENTICATION_TYPE_DATASET_AUTHENTICATION =
181             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION;
182     public static final int AUTHENTICATION_TYPE_FULL_AUTHENTICATION =
183             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION;
184 
185     public static final int AUTHENTICATION_RESULT_UNKNOWN =
186             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN;
187     public static final int AUTHENTICATION_RESULT_SUCCESS =
188             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_SUCCESS;
189     public static final int AUTHENTICATION_RESULT_FAILURE =
190             AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE;
191 
192     public static final int PICK_REASON_UNKNOWN =
193             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_UNKNOWN;
194     public static final int PICK_REASON_NO_PCC =
195             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_NO_PCC;
196      public static final int PICK_REASON_PROVIDER_DETECTION_ONLY =
197              AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_ONLY;
198     public static final int PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC =
199             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PROVIDER_DETECTION_PREFERRED_WITH_PCC;
200     public static final int PICK_REASON_PCC_DETECTION_ONLY =
201             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY;
202     public static final int PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER =
203             AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER;
204 
205 
206     // Values for AutofillFillResponseReported.detection_preference
207     public static final int DETECTION_PREFER_UNKNOWN =
208             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
209     public static final int DETECTION_PREFER_AUTOFILL_PROVIDER =
210             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
211     public static final int DETECTION_PREFER_PCC =
212             AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
213     private final int mSessionId;
214 
215     /**
216      * For app_package_uid.
217      */
218     private final int mCallingAppUid;
219     private Optional<PresentationStatsEventInternal> mEventInternal;
220 
PresentationStatsEventLogger(int sessionId, int callingAppUid)221     private PresentationStatsEventLogger(int sessionId, int callingAppUid) {
222         mSessionId = sessionId;
223         mCallingAppUid = callingAppUid;
224         mEventInternal = Optional.empty();
225     }
226 
227     /**
228      * Create PresentationStatsEventLogger, populated with sessionId and the callingAppUid
229      */
createPresentationLog( int sessionId, int callingAppUid)230     public static PresentationStatsEventLogger createPresentationLog(
231             int sessionId, int callingAppUid) {
232         return new PresentationStatsEventLogger(sessionId, callingAppUid);
233     }
234 
startNewEvent()235     public void startNewEvent() {
236         if (mEventInternal.isPresent()) {
237             Slog.e(TAG, "Failed to start new event because already have active event.");
238             return;
239         }
240         mEventInternal = Optional.of(new PresentationStatsEventInternal());
241     }
242 
maybeSetRequestId(int requestId)243     public void maybeSetRequestId(int requestId) {
244         mEventInternal.ifPresent(event -> event.mRequestId = requestId);
245     }
246 
maybeSetNoPresentationEventReason(@otShownReason int reason)247     public void maybeSetNoPresentationEventReason(@NotShownReason int reason) {
248         mEventInternal.ifPresent(event -> {
249             if (event.mCountShown == 0) {
250                 event.mNoPresentationReason = reason;
251             }
252         });
253     }
254 
maybeSetNoPresentationEventReasonIfNoReasonExists(@otShownReason int reason)255     public void maybeSetNoPresentationEventReasonIfNoReasonExists(@NotShownReason int reason) {
256         mEventInternal.ifPresent(event -> {
257             if (event.mCountShown == 0 && event.mNoPresentationReason == NOT_SHOWN_REASON_UNKNOWN) {
258                 event.mNoPresentationReason = reason;
259             }
260         });
261     }
262 
maybeSetAvailableCount(@ullable List<Dataset> datasetList, AutofillId currentViewId)263     public void maybeSetAvailableCount(@Nullable List<Dataset> datasetList,
264             AutofillId currentViewId) {
265         mEventInternal.ifPresent(event -> {
266             CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId);
267             event.mAvailableCount = container.mAvailableCount;
268             event.mAvailablePccCount = container.mAvailablePccCount;
269             event.mAvailablePccOnlyCount = container.mAvailablePccOnlyCount;
270             event.mIsDatasetAvailable = container.mAvailableCount > 0;
271         });
272     }
273 
maybeSetCountShown(@ullable List<Dataset> datasetList, AutofillId currentViewId)274     public void maybeSetCountShown(@Nullable List<Dataset> datasetList,
275             AutofillId currentViewId) {
276         mEventInternal.ifPresent(event -> {
277             CountContainer container = getDatasetCountForAutofillId(datasetList, currentViewId);
278             event.mCountShown = container.mAvailableCount;
279             if (container.mAvailableCount > 0) {
280                 event.mNoPresentationReason = NOT_SHOWN_REASON_ANY_SHOWN;
281             }
282         });
283     }
284 
getDatasetCountForAutofillId(@ullable List<Dataset> datasetList, AutofillId currentViewId)285     private static CountContainer getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList,
286             AutofillId currentViewId) {
287 
288         CountContainer container = new CountContainer();
289         if (datasetList != null) {
290             for (int i = 0; i < datasetList.size(); i++) {
291                 Dataset data = datasetList.get(i);
292                 if (data != null && data.getFieldIds() != null
293                         && data.getFieldIds().contains(currentViewId)) {
294                     container.mAvailableCount += 1;
295                     if (data.getEligibleReason() == PICK_REASON_PCC_DETECTION_ONLY) {
296                         container.mAvailablePccOnlyCount++;
297                         container.mAvailablePccCount++;
298                     } else if (data.getEligibleReason()
299                             == PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER) {
300                         container.mAvailablePccCount++;
301                     }
302                 }
303             }
304         }
305         return container;
306     }
307 
308     private static class CountContainer{
309         int mAvailableCount = 0;
310         int mAvailablePccCount = 0;
311         int mAvailablePccOnlyCount = 0;
312 
CountContainer()313         CountContainer() {}
314 
CountContainer(int availableCount, int availablePccCount, int availablePccOnlyCount)315         CountContainer(int availableCount, int availablePccCount,
316                 int availablePccOnlyCount) {
317             mAvailableCount = availableCount;
318             mAvailablePccCount = availablePccCount;
319             mAvailablePccOnlyCount = availablePccOnlyCount;
320         }
321     }
322 
maybeSetCountFilteredUserTyping(int countFilteredUserTyping)323     public void maybeSetCountFilteredUserTyping(int countFilteredUserTyping) {
324         mEventInternal.ifPresent(event -> {
325             event.mCountFilteredUserTyping = countFilteredUserTyping;
326         });
327     }
328 
maybeSetCountNotShownImePresentationNotDrawn( int countNotShownImePresentationNotDrawn)329     public void maybeSetCountNotShownImePresentationNotDrawn(
330             int countNotShownImePresentationNotDrawn) {
331         mEventInternal.ifPresent(event -> {
332             event.mCountNotShownImePresentationNotDrawn = countNotShownImePresentationNotDrawn;
333         });
334     }
335 
maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen)336     public void maybeSetCountNotShownImeUserNotSeen(int countNotShownImeUserNotSeen) {
337         mEventInternal.ifPresent(event -> {
338             event.mCountNotShownImeUserNotSeen = countNotShownImeUserNotSeen;
339         });
340     }
341 
maybeSetDisplayPresentationType(@iType int uiType)342     public void maybeSetDisplayPresentationType(@UiType int uiType) {
343         mEventInternal.ifPresent(event -> {
344             event.mDisplayPresentationType = getDisplayPresentationType(uiType);
345         });
346     }
347 
maybeSetFillRequestSentTimestampMs(int timestamp)348     public void maybeSetFillRequestSentTimestampMs(int timestamp) {
349         mEventInternal.ifPresent(event -> {
350             event.mFillRequestSentTimestampMs = timestamp;
351         });
352     }
353 
maybeSetFillResponseReceivedTimestampMs(int timestamp)354     public void maybeSetFillResponseReceivedTimestampMs(int timestamp) {
355         mEventInternal.ifPresent(event -> {
356             event.mFillResponseReceivedTimestampMs = timestamp;
357         });
358     }
359 
maybeSetSuggestionSentTimestampMs(int timestamp)360     public void maybeSetSuggestionSentTimestampMs(int timestamp) {
361         mEventInternal.ifPresent(event -> {
362             event.mSuggestionSentTimestampMs = timestamp;
363         });
364     }
365 
maybeSetSuggestionPresentedTimestampMs(int timestamp)366     public void maybeSetSuggestionPresentedTimestampMs(int timestamp) {
367         mEventInternal.ifPresent(event -> {
368             event.mSuggestionPresentedTimestampMs = timestamp;
369         });
370     }
371 
maybeSetSelectedDatasetId(int selectedDatasetId)372     public void maybeSetSelectedDatasetId(int selectedDatasetId) {
373         mEventInternal.ifPresent(event -> {
374             event.mSelectedDatasetId = selectedDatasetId;
375         });
376     }
377 
maybeSetDialogDismissed(boolean dialogDismissed)378     public void maybeSetDialogDismissed(boolean dialogDismissed) {
379         mEventInternal.ifPresent(event -> {
380             event.mDialogDismissed = dialogDismissed;
381         });
382     }
383 
maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked)384     public void maybeSetNegativeCtaButtonClicked(boolean negativeCtaButtonClicked) {
385         mEventInternal.ifPresent(event -> {
386             event.mNegativeCtaButtonClicked = negativeCtaButtonClicked;
387         });
388     }
389 
maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked)390     public void maybeSetPositiveCtaButtonClicked(boolean positiveCtaButtonClicked) {
391         mEventInternal.ifPresent(event -> {
392             event.mPositiveCtaButtonClicked = positiveCtaButtonClicked;
393         });
394     }
395 
maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId)396     public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) {
397         mEventInternal.ifPresent(event -> {
398             event.mDisplayPresentationType =
399                     AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
400             String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
401                     Settings.Secure.DEFAULT_INPUT_METHOD, userId);
402             if (TextUtils.isEmpty(imeString)) {
403                 Slog.w(TAG, "No default IME found");
404                 return;
405             }
406             ComponentName imeComponent = ComponentName.unflattenFromString(imeString);
407             if (imeComponent == null) {
408                 Slog.w(TAG, "No default IME found");
409                 return;
410             }
411             int imeUid;
412             String packageName = imeComponent.getPackageName();
413             try {
414                 imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName,
415                         PackageManager.ApplicationInfoFlags.of(0), userId).uid;
416             } catch (PackageManager.NameNotFoundException e) {
417                 Slog.w(TAG, "Couldn't find packageName: " + packageName);
418                 return;
419             }
420             event.mInlineSuggestionHostUid = imeUid;
421         });
422     }
423 
maybeSetAutofillServiceUid(int uid)424     public void maybeSetAutofillServiceUid(int uid) {
425         mEventInternal.ifPresent(event -> {
426             event.mAutofillServiceUid = uid;
427         });
428     }
429 
maybeSetIsNewRequest(boolean isRequestTriggered)430     public void maybeSetIsNewRequest(boolean isRequestTriggered) {
431         mEventInternal.ifPresent(event -> {
432             event.mIsRequestTriggered = isRequestTriggered;
433         });
434     }
435 
436     /**
437      * Set authentication_type as long as mEventInternal presents.
438      */
maybeSetAuthenticationType(@uthenticationType int val)439     public void maybeSetAuthenticationType(@AuthenticationType int val) {
440         mEventInternal.ifPresent(event -> {
441             event.mAuthenticationType = val;
442         });
443     }
444 
445     /**
446      * Set authentication_result as long as mEventInternal presents.
447      */
maybeSetAuthenticationResult(@uthenticationResult int val)448     public void maybeSetAuthenticationResult(@AuthenticationResult int val) {
449         mEventInternal.ifPresent(event -> {
450             event.mAuthenticationResult = val;
451         });
452     }
453 
454     /**
455      * Set latency_authentication_ui_display_millis as long as mEventInternal presents.
456      */
maybeSetLatencyAuthenticationUiDisplayMillis(int val)457     public void maybeSetLatencyAuthenticationUiDisplayMillis(int val) {
458         mEventInternal.ifPresent(event -> {
459             event.mLatencyAuthenticationUiDisplayMillis = val;
460         });
461     }
462 
463     /**
464      * Set latency_dataset_display_millis as long as mEventInternal presents.
465      */
maybeSetLatencyDatasetDisplayMillis(int val)466     public void maybeSetLatencyDatasetDisplayMillis(int val) {
467         mEventInternal.ifPresent(event -> {
468             event.mLatencyDatasetDisplayMillis = val;
469         });
470     }
471 
472     /**
473      * Set available_pcc_count.
474      */
maybeSetAvailablePccCount(int val)475     public void maybeSetAvailablePccCount(int val) {
476         mEventInternal.ifPresent(event -> {
477             event.mAvailablePccCount = val;
478         });
479     }
480 
481     /**
482      * Set available_pcc_only_count.
483      */
maybeSetAvailablePccOnlyCount(int val)484     public void maybeSetAvailablePccOnlyCount(int val) {
485         mEventInternal.ifPresent(event -> {
486             event.mAvailablePccOnlyCount = val;
487         });
488     }
489 
490     /**
491      * Set selected_dataset_picked_reason.
492      */
maybeSetSelectedDatasetPickReason(@ataset.DatasetEligibleReason int val)493     public void maybeSetSelectedDatasetPickReason(@Dataset.DatasetEligibleReason int val) {
494         mEventInternal.ifPresent(event -> {
495             event.mSelectedDatasetPickedReason = convertDatasetPickReason(val);
496         });
497     }
498 
499     /**
500      * Set detection_pref
501      */
maybeSetDetectionPreference(@etectionPreference int detectionPreference)502     public void maybeSetDetectionPreference(@DetectionPreference int detectionPreference) {
503         mEventInternal.ifPresent(event -> {
504             event.mDetectionPreference = detectionPreference;
505         });
506     }
507 
convertDatasetPickReason(@ataset.DatasetEligibleReason int val)508     private int convertDatasetPickReason(@Dataset.DatasetEligibleReason int val) {
509         switch (val) {
510             case 0:
511             case 1:
512             case 2:
513             case 3:
514             case 4:
515             case 5:
516                 return val;
517         }
518         return PICK_REASON_UNKNOWN;
519     }
520 
521     /**
522      * Set field_classification_request_id as long as mEventInternal presents.
523      */
maybeSetFieldClassificationRequestId(int requestId)524     public void maybeSetFieldClassificationRequestId(int requestId) {
525         mEventInternal.ifPresent(event -> {
526             event.mFieldClassificationRequestId = requestId;
527         });
528     }
529 
logAndEndEvent()530     public void logAndEndEvent() {
531         if (!mEventInternal.isPresent()) {
532             Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same "
533                     + "event");
534             return;
535         }
536         PresentationStatsEventInternal event = mEventInternal.get();
537         if (sVerbose) {
538             Slog.v(TAG, "Log AutofillPresentationEventReported:"
539                     + " requestId=" + event.mRequestId
540                     + " sessionId=" + mSessionId
541                     + " mNoPresentationEventReason=" + event.mNoPresentationReason
542                     + " mAvailableCount=" + event.mAvailableCount
543                     + " mCountShown=" + event.mCountShown
544                     + " mCountFilteredUserTyping=" + event.mCountFilteredUserTyping
545                     + " mCountNotShownImePresentationNotDrawn="
546                     + event.mCountNotShownImePresentationNotDrawn
547                     + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen
548                     + " mDisplayPresentationType=" + event.mDisplayPresentationType
549                     + " mAutofillServiceUid=" + event.mAutofillServiceUid
550                     + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid
551                     + " mIsRequestTriggered=" + event.mIsRequestTriggered
552                     + " mFillRequestSentTimestampMs=" + event.mFillRequestSentTimestampMs
553                     + " mFillResponseReceivedTimestampMs=" + event.mFillResponseReceivedTimestampMs
554                     + " mSuggestionSentTimestampMs=" + event.mSuggestionSentTimestampMs
555                     + " mSuggestionPresentedTimestampMs=" + event.mSuggestionPresentedTimestampMs
556                     + " mSelectedDatasetId=" + event.mSelectedDatasetId
557                     + " mDialogDismissed=" + event.mDialogDismissed
558                     + " mNegativeCtaButtonClicked=" + event.mNegativeCtaButtonClicked
559                     + " mPositiveCtaButtonClicked=" + event.mPositiveCtaButtonClicked
560                     + " mAuthenticationType=" + event.mAuthenticationType
561                     + " mAuthenticationResult=" + event.mAuthenticationResult
562                     + " mLatencyAuthenticationUiDisplayMillis="
563                     + event.mLatencyAuthenticationUiDisplayMillis
564                     + " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis
565                     + " mAvailablePccCount=" + event.mAvailablePccCount
566                     + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount
567                     + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason
568                     + " mDetectionPreference=" + event.mDetectionPreference
569                     + " mFieldClassificationRequestId=" + event.mFieldClassificationRequestId
570                     + " mAppPackageUid=" + mCallingAppUid);
571         }
572 
573         // TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
574         if (!event.mIsDatasetAvailable) {
575             mEventInternal = Optional.empty();
576             return;
577         }
578         FrameworkStatsLog.write(
579                 AUTOFILL_PRESENTATION_EVENT_REPORTED,
580                 event.mRequestId,
581                 mSessionId,
582                 event.mNoPresentationReason,
583                 event.mAvailableCount,
584                 event.mCountShown,
585                 event.mCountFilteredUserTyping,
586                 event.mCountNotShownImePresentationNotDrawn,
587                 event.mCountNotShownImeUserNotSeen,
588                 event.mDisplayPresentationType,
589                 event.mAutofillServiceUid,
590                 event.mInlineSuggestionHostUid,
591                 event.mIsRequestTriggered,
592                 event.mFillRequestSentTimestampMs,
593                 event.mFillResponseReceivedTimestampMs,
594                 event.mSuggestionSentTimestampMs,
595                 event.mSuggestionPresentedTimestampMs,
596                 event.mSelectedDatasetId,
597                 event.mDialogDismissed,
598                 event.mNegativeCtaButtonClicked,
599                 event.mPositiveCtaButtonClicked,
600                 event.mAuthenticationType,
601                 event.mAuthenticationResult,
602                 event.mLatencyAuthenticationUiDisplayMillis,
603                 event.mLatencyDatasetDisplayMillis,
604                 event.mAvailablePccCount,
605                 event.mAvailablePccOnlyCount,
606                 event.mSelectedDatasetPickedReason,
607                 event.mDetectionPreference,
608                 event.mFieldClassificationRequestId,
609                 mCallingAppUid);
610         mEventInternal = Optional.empty();
611     }
612 
613     private static final class PresentationStatsEventInternal {
614         int mRequestId;
615         @NotShownReason int mNoPresentationReason = NOT_SHOWN_REASON_UNKNOWN;
616         boolean mIsDatasetAvailable;
617         int mAvailableCount;
618         int mCountShown;
619         int mCountFilteredUserTyping;
620         int mCountNotShownImePresentationNotDrawn;
621         int mCountNotShownImeUserNotSeen;
622         int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
623         int mAutofillServiceUid = -1;
624         int mInlineSuggestionHostUid = -1;
625         boolean mIsRequestTriggered;
626         int mFillRequestSentTimestampMs;
627         int mFillResponseReceivedTimestampMs;
628         int mSuggestionSentTimestampMs;
629         int mSuggestionPresentedTimestampMs;
630         int mSelectedDatasetId = -1;
631         boolean mDialogDismissed = false;
632         boolean mNegativeCtaButtonClicked = false;
633         boolean mPositiveCtaButtonClicked = false;
634         int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN;
635         int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN;
636         int mLatencyAuthenticationUiDisplayMillis = -1;
637         int mLatencyDatasetDisplayMillis = -1;
638         int mAvailablePccCount = -1;
639         int mAvailablePccOnlyCount = -1;
640         @DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN;
641         @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN;
642         int mFieldClassificationRequestId = -1;
643 
PresentationStatsEventInternal()644         PresentationStatsEventInternal() {}
645     }
646 
getNoPresentationEventReason( @utofillManager.AutofillCommitReason int commitReason)647     static int getNoPresentationEventReason(
648             @AutofillManager.AutofillCommitReason int commitReason) {
649         switch (commitReason) {
650             case COMMIT_REASON_VIEW_COMMITTED:
651                 return NOT_SHOWN_REASON_SESSION_COMMITTED_PREMATURELY;
652             case COMMIT_REASON_ACTIVITY_FINISHED:
653                 return NOT_SHOWN_REASON_ACTIVITY_FINISHED;
654             case COMMIT_REASON_VIEW_CHANGED:
655                 return NOT_SHOWN_REASON_VIEW_CHANGED;
656             case COMMIT_REASON_VIEW_CLICKED:
657                 // TODO(b/234185326): Add separate reason for view clicked.
658             default:
659                 return NOT_SHOWN_REASON_UNKNOWN;
660         }
661     }
662 
getDisplayPresentationType(@iType int uiType)663     private static int getDisplayPresentationType(@UiType int uiType) {
664         switch (uiType) {
665             case UI_TYPE_MENU:
666                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
667             case UI_TYPE_INLINE:
668                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
669             case UI_TYPE_DIALOG:
670                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
671             default:
672                 return AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
673         }
674     }
675 }
676