Merge "Autofill Presentation Logs 3" into main
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index 676abd1..d7da2f0 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -295,6 +295,38 @@
         });
     }
 
+    /**
+     * Called for inline suggestions - inflated one at
+     * a time. If InlineSuggestions were filtered,
+     * reset the count be incrementing
+     */
+    public void maybeIncrementCountShown() {
+        mEventInternal.ifPresent(event -> {
+            if (event.shouldResetShownCount) {
+                event.shouldResetShownCount = false;
+                event.mCountShown = 0;
+            }
+
+            if (event.mCountShown == 0) {
+                // The first time suggestions are rendered
+                // set time stamp
+                maybeSetSuggestionPresentedTimestampMs();
+            }
+
+            event.mCountShown += 1;
+        });
+    }
+
+    /**
+     * Call this when UI is hidden. This will set a flag to reset count for inline. We do this
+     * instead of resetting right away in case there are 0 inline presentations after.
+     */
+    public void markShownCountAsResettable() {
+        mEventInternal.ifPresent(event -> {
+            event.shouldResetShownCount = true;
+        });
+    }
+
     public void maybeSetCountShown(@Nullable List<Dataset> datasetList,
             AutofillId currentViewId) {
         mEventInternal.ifPresent(event -> {
@@ -306,6 +338,13 @@
         });
     }
 
+    public void maybeSetCountShown(int datasets) {
+        mEventInternal.ifPresent(
+                event -> {
+                    event.mCountShown = datasets;
+                });
+    }
+
     private static CountContainer getDatasetCountForAutofillId(@Nullable List<Dataset> datasetList,
             AutofillId currentViewId) {
 
@@ -567,31 +606,36 @@
      * <p>If the ViewState contains ViewState.STATE_AUTOFILLED, sets field_autofilled_timestamp_ms
      * else, set field_first_modified_timestamp_ms (if unset) and field_last_modified_timestamp_ms
      */
-    public void onFieldTextUpdated(ViewState state) {
-        mEventInternal.ifPresent(
-                event -> {
+    public void onFieldTextUpdated(ViewState state, int length) {
+        mEventInternal.ifPresent(event -> {
                     int timestamp = getElapsedTime();
                     // Focused id should be set before this is called
-                    if (state.id != null && state.id.getViewId() != event.mFocusedId) {
+                    if (state == null || state.id == null || state.id.getViewId() != event.mFocusedId) {
                         // if these don't match, the currently field different than before
                         Slog.w(
                                 TAG,
-                                "current id: "
-                                        + state.id.getViewId()
-                                        + " is different than focused id: "
-                                        + event.mFocusedId);
+                                "Bad view state for: " + event.mFocusedId);
                         return;
                     }
 
+                    // Text changed because filling into form, just log Autofill timestamp
                     if ((state.getState() & ViewState.STATE_AUTOFILLED) != 0) {
                         event.mAutofilledTimestampMs = timestamp;
-                    } else {
-                        if (event.mFieldModifiedFirstTimestampMs == DEFAULT_VALUE_INT) {
-                            event.mFieldModifiedFirstTimestampMs = timestamp;
-                        }
-                        event.mFieldModifiedLastTimestampMs = timestamp;
+                        return;
                     }
-                });
+
+                    // Set length variables
+                    if (event.mFieldFirstLength == DEFAULT_VALUE_INT) {
+                        event.mFieldFirstLength = length;
+                    }
+                    event.mFieldLastLength = length;
+
+                    // Set timestamp variables
+                    if (event.mFieldModifiedFirstTimestampMs == DEFAULT_VALUE_INT) {
+                        event.mFieldModifiedFirstTimestampMs = timestamp;
+                    }
+                    event.mFieldModifiedLastTimestampMs = timestamp;
+        });
     }
 
     public void setPresentationSelectedTimestamp() {
@@ -661,15 +705,16 @@
 
     /** Sets focused_autofill_id using view id */
     public void maybeSetFocusedId(AutofillId id) {
-        maybeSetFocusedId(id.getViewId());
+        mEventInternal.ifPresent(
+                event -> {
+                    event.mFocusedId = id.getViewId();
+                    if (id.isVirtualInt()) {
+                        event.mFocusedVirtualAutofillId =
+                                id.getVirtualChildIntId() % 100;
+                    }
+                });
     }
 
-    /** Sets focused_autofill_id as long as mEventInternal is present */
-    public void maybeSetFocusedId(int id) {
-        mEventInternal.ifPresent(event -> {
-            event.mFocusedId = id;
-        });
-    }
     /**
      * Set views_filled_failure_count using failure count as long as mEventInternal
      * presents.
@@ -823,7 +868,7 @@
         @NotShownReason int mNoPresentationReason = NOT_SHOWN_REASON_UNKNOWN;
         boolean mIsDatasetAvailable;
         int mAvailableCount;
-        int mCountShown;
+        int mCountShown = 0;
         int mCountFilteredUserTyping;
         int mCountNotShownImePresentationNotDrawn;
         int mCountNotShownImeUserNotSeen;
@@ -870,6 +915,9 @@
 
         ArraySet<AutofillId> mAutofillIdsAttemptedAutofill;
         ArraySet<AutofillId> mAlreadyFilledAutofillIds = new ArraySet<>();
+
+        // Not logged - used for internal logic
+        boolean shouldResetShownCount = false;
         PresentationStatsEventInternal() {}
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index b22f999..cdae16b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -30,7 +30,6 @@
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_CREDMAN_BOTTOM_SHEET;
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
-import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
 import static android.service.autofill.FillEventHistory.Event.UI_TYPE_UNKNOWN;
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
@@ -2661,19 +2660,30 @@
 
     // AutofillUiCallback
     @Override
-    public void onShown(int uiType) {
+    public void onShown(int uiType, int numDatasetsShown) {
         synchronized (mLock) {
+            mPresentationStatsEventLogger.maybeSetDisplayPresentationType(uiType);
+
             if (uiType == UI_TYPE_INLINE) {
-                if (mLoggedInlineDatasetShown) {
+                // Inline Suggestions are inflated one at a time
+                // This number will be reset when filtered
+                // This will also call maybeSetSuggestionPresentedTimestampMs
+                mPresentationStatsEventLogger.maybeIncrementCountShown();
+
+                if (!mLoggedInlineDatasetShown) {
                     // Chip inflation already logged, do not log again.
                     // This is needed because every chip inflation will call this.
-                    return;
+                    mService.logDatasetShown(this.id, mClientState, uiType);
+                    Slog.d(TAG, "onShown(): " + uiType + ", " + numDatasetsShown);
                 }
                 mLoggedInlineDatasetShown = true;
+            } else {
+                mPresentationStatsEventLogger.maybeSetCountShown(numDatasetsShown);
+                // Explicitly sets maybeSetSuggestionPresentedTimestampMs
+                mPresentationStatsEventLogger.maybeSetSuggestionPresentedTimestampMs();
+                mService.logDatasetShown(this.id, mClientState, uiType);
+                Slog.d(TAG, "onShown(): " + uiType + ", " + numDatasetsShown);
             }
-            mService.logDatasetShown(this.id, mClientState, uiType);
-            mPresentationStatsEventLogger.maybeSetSuggestionPresentedTimestampMs();
-            Slog.d(TAG, "onShown(): " + uiType);
         }
     }
 
@@ -2739,6 +2749,7 @@
             }
 
             mInlineSessionController.hideInlineSuggestionsUiLocked(id);
+            mPresentationStatsEventLogger.markShownCountAsResettable();
         }
     }
 
@@ -4868,7 +4879,9 @@
                 currentView.maybeCallOnFillReady(flags);
             }
         }
-        mPresentationStatsEventLogger.onFieldTextUpdated(viewState);
+        if (textValue != null) {
+            mPresentationStatsEventLogger.onFieldTextUpdated(viewState, textValue.length());
+        }
 
         if (viewState.id.equals(this.mCurrentViewId)
                 && (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
@@ -4965,8 +4978,6 @@
                 synchronized (mLock) {
                     final ViewState currentView = mViewStates.get(mCurrentViewId);
                     currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
-                    mPresentationStatsEventLogger.maybeSetCountShown(
-                            response.getDatasets(), mCurrentViewId);
                     mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_DIALOG);
                 }
                 // Just show fill dialog once, so disabled after shown.
@@ -4987,10 +4998,6 @@
                     // back a response via callback.
                     final ViewState currentView = mViewStates.get(mCurrentViewId);
                     currentView.setState(ViewState.STATE_INLINE_SHOWN);
-                    // TODO(b/234475358): Log more accurate value of number of inline suggestions
-                    // shown, inflated, and filtered.
-                    mPresentationStatsEventLogger.maybeSetCountShown(
-                            response.getDatasets(), mCurrentViewId);
                     mPresentationStatsEventLogger.maybeSetInlinePresentationAndSuggestionHostUid(
                             mContext, userId);
                     return;
@@ -5004,12 +5011,6 @@
                 mService.getMaster().getMaxInputLengthForAutofill());
 
         synchronized (mLock) {
-            mPresentationStatsEventLogger.maybeSetCountShown(
-                    response.getDatasets(), mCurrentViewId);
-            mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_MENU);
-        }
-
-        synchronized (mLock) {
             if (mUiShownTime == 0) {
                 // Log first time UI is shown.
                 mUiShownTime = SystemClock.elapsedRealtime();
@@ -5249,7 +5250,7 @@
 
                     @Override
                     public void onInflate() {
-                        Session.this.onShown(UI_TYPE_INLINE);
+                        Session.this.onShown(UI_TYPE_INLINE, 1);
                     }
                 }, mService.getMaster().getMaxInputLengthForAutofill());
         return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 8cc666b..2e9a4dc 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -102,7 +102,7 @@
         void cancelSession();
         void requestShowSoftInput(AutofillId id);
         void requestFallbackFromFillDialog();
-        void onShown(int uiType);
+        void onShown(int uiType, int datasetSize);
     }
 
     public AutoFillUI(@NonNull Context context) {
@@ -246,9 +246,9 @@
                 }
 
                 @Override
-                public void onShown() {
+                public void onShown(int datasetSize) {
                     if (mCallback != null) {
-                        mCallback.onShown(UI_TYPE_MENU);
+                        mCallback.onShown(UI_TYPE_MENU, datasetSize);
                     }
                 }
 
@@ -462,7 +462,7 @@
 
                         @Override
                         public void onShown() {
-                            callback.onShown(UI_TYPE_DIALOG);
+                            mCallback.onShown(UI_TYPE_DIALOG, response.getDatasets().size());
                         }
 
                         @Override
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 1831ecd..1bda70d 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -16,6 +16,7 @@
 package com.android.server.autofill.ui;
 
 import static android.service.autofill.FillResponse.FLAG_CREDENTIAL_MANAGER_RESPONSE;
+
 import static com.android.server.autofill.Helper.paramsToString;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sFullScreenMode;
@@ -90,7 +91,7 @@
         void onDatasetPicked(@NonNull Dataset dataset);
         void onCanceled();
         void onDestroy();
-        void onShown();
+        void onShown(int datasetSize);
         void requestShowFillUi(int width, int height,
                 IAutofillWindowPresenter windowPresenter);
         void requestHideFillUi();
@@ -742,7 +743,8 @@
                     mWm.addView(mContentView, params);
                     mOverlayControl.hideOverlays();
                     mShowing = true;
-                    mCallback.onShown();
+                    int numShownDatasets = (mAdapter == null) ? 0 : mAdapter.getCount();
+                    mCallback.onShown(numShownDatasets);
                 } else {
                     mWm.updateViewLayout(mContentView, params);
                 }