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