diff options
| author | 2024-12-06 03:36:30 +0000 | |
|---|---|---|
| committer | 2024-12-06 03:36:30 +0000 | |
| commit | 4110ab51d8da8518b17b985528f904697de1226d (patch) | |
| tree | f0f2a95a0d031a2bd43438c45db2680e3a509ed6 | |
| parent | 96d9fdc4c5a3e1128f36f9b1f7330d85dcdbc7c6 (diff) | |
| parent | 03415d12e48037a5ba416c4e5770d2c1042a5b2b (diff) | |
Merge "[Fill Dialog Improvements] Implement Fill Dialog improvements" into main
8 files changed, 379 insertions, 34 deletions
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 1de0474182dd..60e528c5fb58 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -26,6 +26,7 @@ import static android.service.autofill.FillRequest.FLAG_SUPPORTS_FILL_DIALOG; import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE; import static android.service.autofill.Flags.FLAG_FILL_DIALOG_IMPROVEMENTS; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.service.autofill.Flags.relayoutFix; import static android.view.ContentInfo.SOURCE_AUTOFILL; import static android.view.autofill.Helper.sDebug; @@ -787,6 +788,11 @@ public final class AutofillManager { private AutofillStateFingerprint mAutofillStateFingerprint; + /** + * Whether improveFillDialog feature is enabled or not. + */ + private boolean mImproveFillDialogEnabled; + /** @hide */ public interface AutofillClient { /** @@ -1017,6 +1023,17 @@ public final class AutofillManager { mRelayoutFix = relayoutFix() && AutofillFeatureFlags.enableRelayoutFixes(); mRelativePositionForRelayout = AutofillFeatureFlags.enableRelativeLocationForRelayout(); mIsCredmanIntegrationEnabled = Flags.autofillCredmanIntegration(); + mImproveFillDialogEnabled = + improveFillDialogAconfig() && AutofillFeatureFlags.isImproveFillDialogEnabled(); + } + + /** + * Whether improvement to fill dialog is enabled. + * + * @hide + */ + public boolean isImproveFillDialogEnabled() { + return mImproveFillDialogEnabled; } /** @@ -1679,6 +1696,11 @@ public final class AutofillManager { private void notifyViewReadyInner(AutofillId id, @Nullable String[] autofillHints, boolean isCredmanRequested) { + if (isImproveFillDialogEnabled() && !isCredmanRequested) { + // We do not want to send pre-trigger request. + // TODO(b/377868687): verify if we can remove the flow for isCredmanRequested too. + return; + } if (sDebug) { Log.d(TAG, "notifyViewReadyInner:" + id); } @@ -2046,6 +2068,34 @@ public final class AutofillManager { } /** + * Notify autofill system that IME animation has started + * @param startTimeMs start time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationStart(long startTimeMs) { + try { + mService.notifyImeAnimationStart(mSessionId, startTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + + /** + * Notify autofill system that IME animation has ended + * @param endTimeMs end time as measured by SystemClock.elapsedRealtime() + */ + void notifyImeAnimationEnd(long endTimeMs) { + try { + mService.notifyImeAnimationEnd(mSessionId, endTimeMs, mContext.getUserId()); + } catch (RemoteException e) { + // The failure could be a consequence of something going wrong on the + // server side. Just log the exception and move-on. + Log.w(TAG, "notifyImeAnimationStart(): RemoteException caught but ignored " + e); + } + } + + /** * Called when a virtual view that supports autofill is exited. * * @param view the virtual view parent. @@ -4050,6 +4100,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, view.getAutofillId())) { mShowAutofillDialogCalled = true; @@ -4093,6 +4147,10 @@ public final class AutofillManager { @FlaggedApi(FLAG_FILL_DIALOG_IMPROVEMENTS) @Deprecated public boolean showAutofillDialog(@NonNull View view, int virtualId) { + if (isImproveFillDialogEnabled()) { + Log.i(TAG, "showAutofillDialog() return false due to improve fill dialog"); + return false; + } Objects.requireNonNull(view); if (shouldShowAutofillDialog(view, getAutofillId(view, virtualId))) { mShowAutofillDialogCalled = true; @@ -4117,7 +4175,7 @@ public final class AutofillManager { return false; } - if (getImeStateFlag(view) == FLAG_IME_SHOWING) { + if (getImeStateFlag(view) == FLAG_IME_SHOWING && !isImproveFillDialogEnabled()) { // IME is showing return false; } diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index f67405f7c1e4..28f8577beed7 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -70,4 +70,6 @@ oneway interface IAutoFillManager { void notifyNotExpiringResponseDuringAuth(int sessionId, int userId); void notifyViewEnteredIgnoredDuringAuthCount(int sessionId, int userId); void setAutofillIdsAttemptedForRefill(int sessionId, in List<AutofillId> ids, int userId); + void notifyImeAnimationStart(int sessionId, long startTimeMs, int userId); + void notifyImeAnimationEnd(int sessionId, long endTimeMs, int userId); } diff --git a/services/autofill/bugfixes.aconfig b/services/autofill/bugfixes.aconfig index 5e1b1473d233..9c83757f4b0f 100644 --- a/services/autofill/bugfixes.aconfig +++ b/services/autofill/bugfixes.aconfig @@ -9,6 +9,16 @@ flag { } flag { + name: "improve_fill_dialog_aconfig" + namespace: "autofill" + description: "Improvements for Fill Dialog. Guard DeviceConfig rollout " + bug: "382493181" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "fill_fields_from_current_session_only" namespace: "autofill" description: "Only fill autofill fields that are part of the current session." diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java index 219b788448e8..5e7e557d7041 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java +++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java @@ -354,6 +354,13 @@ final class AutofillInlineSuggestionsRequestSession { } } + private void handleOnInputMethodStartInputView() { + synchronized (mLock) { + mUiCallback.onInputMethodStartInputView(); + handleOnReceiveImeStatusUpdated(true, true); + } + } + /** * Handles the IME session status received from the IME. * @@ -437,8 +444,8 @@ final class AutofillInlineSuggestionsRequestSession { final AutofillInlineSuggestionsRequestSession session = mSession.get(); if (session != null) { session.mHandler.sendMessage(obtainMessage( - AutofillInlineSuggestionsRequestSession::handleOnReceiveImeStatusUpdated, - session, true, true)); + AutofillInlineSuggestionsRequestSession::handleOnInputMethodStartInputView, + session)); } } diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 259ea148f163..cba8c66cd5e3 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -2139,6 +2139,32 @@ public final class AutofillManagerService } @Override + public void notifyImeAnimationStart(int sessionId, long startTimeMs, int userId) { + synchronized (mLock) { + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationStart(sessionId, startTimeMs, getCallingUid()); + } else if (sVerbose) { + Slog.v(TAG, "notifyImeAnimationStart(): no service for " + userId); + } + } + } + + @Override + public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int userId) { + synchronized (mLock) { + final AutofillManagerServiceImpl service = + peekServiceForUserWithLocalBinderIdentityLocked(userId); + if (service != null) { + service.notifyImeAnimationEnd(sessionId, endTimeMs, getCallingUid()); + } else if (sVerbose) { + Slog.v(TAG, "notifyImeAnimationEnd(): no service for " + userId); + } + } + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 5cf96bfb2b8b..0fa43ac7091b 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -823,6 +823,36 @@ final class AutofillManagerServiceImpl } @GuardedBy("mLock") + public void notifyImeAnimationStart(int sessionId, long startTimeMs, int uid) { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(sessionId); + if (session == null || uid != session.uid) { + Slog.v(TAG, "notifyImeAnimationStart(): no session for " + + sessionId + "(" + uid + ")"); + return; + } + session.notifyImeAnimationStart(startTimeMs); + } + + @GuardedBy("mLock") + public void notifyImeAnimationEnd(int sessionId, long endTimeMs, int uid) { + if (!isEnabledLocked()) { + Slog.wtf(TAG, "Service not enabled"); + return; + } + final Session session = mSessions.get(sessionId); + if (session == null || uid != session.uid) { + Slog.v(TAG, "notifyImeAnimationEnd(): no session for " + + sessionId + "(" + uid + ")"); + return; + } + session.notifyImeAnimationEnd(endTimeMs); + } + + @GuardedBy("mLock") @Override // from PerUserSystemService protected void handlePackageUpdateLocked(@NonNull String packageName) { final ServiceInfo serviceInfo = mFieldClassificationStrategy.getServiceInfo(); diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 6b227d7a876e..9c6e4741730a 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -40,6 +40,7 @@ import static android.service.autofill.FillRequest.FLAG_VIEW_NOT_FOCUSED; import static android.service.autofill.FillRequest.FLAG_VIEW_REQUESTS_CREDMAN_SERVICE; import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; import static android.service.autofill.Flags.highlightAutofillSingleField; +import static android.service.autofill.Flags.improveFillDialogAconfig; import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED; import static android.view.autofill.AutofillManager.ACTION_START_SESSION; import static android.view.autofill.AutofillManager.ACTION_VALUE_CHANGED; @@ -50,6 +51,7 @@ import static android.view.autofill.AutofillManager.COMMIT_REASON_UNKNOWN; import static android.view.autofill.AutofillManager.EXTRA_AUTOFILL_REQUEST_ID; import static android.view.autofill.AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM; import static android.view.autofill.AutofillManager.getSmartSuggestionModeToString; + import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_EXPLICITLY_REQUESTED; import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_NORMAL_TRIGGER; @@ -184,6 +186,7 @@ import android.view.autofill.IAutoFillManagerClient; import android.view.autofill.IAutofillWindowPresenter; import android.view.inputmethod.InlineSuggestionsRequest; import android.widget.RemoteViews; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; @@ -195,6 +198,7 @@ import com.android.server.autofill.ui.InlineFillUi; import com.android.server.autofill.ui.PendingUi; import com.android.server.inputmethod.InputMethodManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; + import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -248,6 +252,8 @@ final class Session private static final int DEFAULT__FILL_REQUEST_ID_SNAPSHOT = -2; private static final int DEFAULT__FIELD_CLASSIFICATION_REQUEST_ID_SNAPSHOT = -2; + private static final long DEFAULT_UNASSIGNED_TIME = -1; + static final String SESSION_ID_KEY = "autofill_session_id"; static final String REQUEST_ID_KEY = "autofill_request_id"; @@ -292,6 +298,31 @@ final class Session @Retention(RetentionPolicy.SOURCE) @interface SessionState {} + /** + * Indicates fill dialog will not be shown. + */ + private static final int SHOW_FILL_DIALOG_NO = 0; + + /** + * Indicates fill dialog is shown. + */ + private static final int SHOW_FILL_DIALOG_YES = 1; + + /** + * Indicates fill dialog can be shown, but we need to wait. + * For eg, if the IME animation is happening, we need for it to complete before fill dialog can + * be shown. + */ + private static final int SHOW_FILL_DIALOG_WAIT = 2; + + @IntDef(prefix = { "SHOW_FILL_DIALOG_" }, value = { + SHOW_FILL_DIALOG_NO, + SHOW_FILL_DIALOG_YES, + SHOW_FILL_DIALOG_WAIT + }) + @Retention(RetentionPolicy.SOURCE) + private @interface ShowFillDialogState{} + @GuardedBy("mLock") private final SessionFlags mSessionFlags; @@ -576,6 +607,47 @@ final class Session private boolean mIgnoreViewStateResetToEmpty; + /** + * Whether improveFillDialog feature is enabled or not. + * Configured via device config flag and aconfig flag. + */ + private final boolean mImproveFillDialogEnabled; + + /** + * Timeout, after which, fill dialog won't be shown. + * Configured via device config flag. + */ + private final long mFillDialogTimeoutMs; + + /** + * Time to wait after ime Animation ends before showing up fill dialog. + * Configured via device config flag. + */ + private final long mFillDialogMinWaitAfterImeAnimationMs; + + /** + * Indicates the need to wait for ime animation to end before showing up fill dialog. + * This is set when we receive notification of ime animation start. + * Focussing on one input field from another wouldn't cause ime to re-animate. So this will let + * us know whether we need to wait for ime animation finish notification. + */ + private boolean mWaitForImeAnimation; + + /** + * A runnable set to run when there is a need to wait for ime animation to end before showing + * up fill dialog. This is set only if the fill response has been received, and the response + * is eligible for showing up fill dialog, but the ime animation hasn't completed. This allows + * for this runnable to be scheduled/run when the ime animation ends, in order to show fill + * dialog. + */ + private Runnable mFillDialogRunnable; + + private long mImeAnimationFinishTimeMs = DEFAULT_UNASSIGNED_TIME; + + private long mImeAnimationStartTimeMs = DEFAULT_UNASSIGNED_TIME; + + private long mLastInputStartTime = DEFAULT_UNASSIGNED_TIME; + /* * Id of the previous view that was entered. Once set, it would only be replaced by non-null * view ids. @@ -1493,6 +1565,12 @@ final class Session // Now request the assist structure data. requestAssistStructureLocked(requestId, flags); + if (mImproveFillDialogEnabled) { + // New request has been sent, so re-enable fill dialog. + // Fill dialog is eligible to be shown after each Fill request. + enableFillDialog(); + } + return Optional.of(requestId); } @@ -1657,6 +1735,11 @@ final class Session mSaveEventLogger = SaveEventLogger.forSessionId(sessionId, mLatencyBaseTime); mIsPrimaryCredential = isPrimaryCredential; mIgnoreViewStateResetToEmpty = AutofillFeatureFlags.shouldIgnoreViewStateResetToEmpty(); + mImproveFillDialogEnabled = + improveFillDialogAconfig() && AutofillFeatureFlags.isImproveFillDialogEnabled(); + mFillDialogTimeoutMs = AutofillFeatureFlags.getFillDialogTimeoutMs(); + mFillDialogMinWaitAfterImeAnimationMs = + AutofillFeatureFlags.getFillDialogMinWaitAfterImeAnimationtEndMs(); synchronized (mLock) { mSessionFlags = new SessionFlags(); @@ -1682,6 +1765,13 @@ final class Session public void notifyInlineUiHidden(AutofillId autofillId) { notifyFillUiHidden(autofillId); } + + @Override + public void onInputMethodStartInputView() { + // TODO(b/377868687): This method isn't called when IME doesn't + // support inline suggestion. Handle those cases as well. + onInputMethodStart(); + } }); mMetricsLogger.write( @@ -3044,6 +3134,12 @@ final class Session } } + private void onInputMethodStart() { + synchronized (mLock) { + mLastInputStartTime = SystemClock.elapsedRealtime(); + } + } + private void doStartIntentSender(IntentSender intentSender, Intent intent) { try { synchronized (mLock) { @@ -5407,6 +5503,15 @@ final class Session } } + private void resetImeAnimationState() { + synchronized (mLock) { + mWaitForImeAnimation = false; + mImeAnimationStartTimeMs = DEFAULT_UNASSIGNED_TIME; + mImeAnimationFinishTimeMs = DEFAULT_UNASSIGNED_TIME; + mLastInputStartTime = DEFAULT_UNASSIGNED_TIME; + } + } + @Override public void onFillReady( @NonNull FillResponse response, @@ -5452,18 +5557,24 @@ final class Session final AutofillId[] ids = response.getFillDialogTriggerIds(); if (ids != null && ArrayUtils.contains(ids, filledId)) { - if (requestShowFillDialog(response, filledId, filterText, flags)) { + @ShowFillDialogState int fillDialogState = + requestShowFillDialog(response, filledId, filterText, flags); + if (fillDialogState == SHOW_FILL_DIALOG_YES) { synchronized (mLock) { final ViewState currentView = mViewStates.get(mCurrentViewId); currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN); } - // Just show fill dialog once, so disabled after shown. + // Just show fill dialog once per fill request, so disabled after shown. // Note: Cannot disable before requestShowFillDialog() because the method - // need to check whether fill dialog enabled. + // need to check whether fill dialog is enabled. setFillDialogDisabled(); + resetImeAnimationState(); return; - } else { + } else if (fillDialogState == SHOW_FILL_DIALOG_NO) { + resetImeAnimationState(); setFillDialogDisabled(); + } else { // SHOW_FILL_DIALOG_WAIT + return; } } @@ -5559,7 +5670,20 @@ final class Session } } + private void enableFillDialog() { + if (sVerbose) { + Slog.v(TAG, "Enabling Fill Dialog...."); + } + synchronized (mLock) { + mSessionFlags.mFillDialogDisabled = false; + } + notifyClientFillDialogTriggerIds(null); + } + private void setFillDialogDisabled() { + if (sVerbose) { + Slog.v(TAG, "Disabling Fill Dialog."); + } synchronized (mLock) { mSessionFlags.mFillDialogDisabled = true; } @@ -5577,24 +5701,28 @@ final class Session } } - private boolean requestShowFillDialog( + private @ShowFillDialogState int requestShowFillDialog( FillResponse response, AutofillId filledId, String filterText, int flags) { if (!isFillDialogUiEnabled()) { + // TODO(b/377868687): The above check includes credman fields. We may want to show + // credman fields again. // Unsupported fill dialog UI - if (sDebug) Log.w(TAG, "requestShowFillDialog: fill dialog is disabled"); - return false; + if (sDebug) Log.w(TAG, "requestShowFillDialog(): fill dialog is disabled"); + return SHOW_FILL_DIALOG_NO; } - if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) { - // IME is showing, fallback to normal suggestions UI - if (sDebug) Log.w(TAG, "requestShowFillDialog: IME is showing"); - return false; - } + if (!mImproveFillDialogEnabled) { + if ((flags & FillRequest.FLAG_IME_SHOWING) != 0) { + // IME is showing, fallback to normal suggestions UI + if (sDebug) Log.w(TAG, "requestShowFillDialog(): IME is showing"); + return SHOW_FILL_DIALOG_NO; + } - if (mInlineSessionController.isImeShowing()) { - // IME is showing, fallback to normal suggestions UI - // Note: only work when inline suggestions supported - return false; + if (mInlineSessionController.isImeShowing()) { + // IME is showing, fallback to normal suggestions UI + // Note: only work when inline suggestions supported + return SHOW_FILL_DIALOG_NO; + } } synchronized (mLock) { @@ -5602,29 +5730,84 @@ final class Session || !ArrayUtils.contains(mLastFillDialogTriggerIds, filledId)) { // Last fill dialog triggered ids are changed. if (sDebug) Log.w(TAG, "Last fill dialog triggered ids are changed."); - return false; + return SHOW_FILL_DIALOG_NO; + } + + if (mImproveFillDialogEnabled && mInlineSessionController.isImeShowing()) { + long currentTimestampMs = SystemClock.elapsedRealtime(); + long durationMs = currentTimestampMs - mLastInputStartTime; + if (sVerbose) { + Log.d(TAG, "IME is showing. Checking for elapsed time "); + Log.d(TAG, "IME is showing. Timestamps start: " + mLastInputStartTime + + " current: " + currentTimestampMs + " duration: " + durationMs + + " mFillDialogTimeoutMs: " + mFillDialogTimeoutMs); + } + + // Following situations can arise wrt IME animation. + // 1. No animation happening (eg IME already animated). In that case, + // mWaitForImeAnimation should be false. This is possible if the IME is already up + // on a field, but the user focusses on another field. Under such condition, + // since IME has already animated, there won't be another animation. However, + // onInputStartInputView is still called. + // 2. Animation is still proceeding. We should wait for animation to finish, + // and then proceed. + // 3. Animation is complete. + if (mWaitForImeAnimation) { + // we need to wait for animation to happen. We can't return from here yet. + // This is the situation #2 described above. + Log.d(TAG, "Waiting for ime animation to complete before showing fill dialog"); + mFillDialogRunnable = createFillDialogEvalRunnable( + response, filledId, filterText, flags); + return SHOW_FILL_DIALOG_WAIT; + } + + // Incorporate situations 1 & 3 discussed above. We calculate the duration from the + // max of start input time or the ime finish time + long effectiveDuration = currentTimestampMs + - Math.max(mLastInputStartTime, mImeAnimationFinishTimeMs); + if (effectiveDuration >= mFillDialogTimeoutMs) { + Log.d(TAG, "Fill dialog not shown since IME has been up for more time than " + + mFillDialogTimeoutMs + "ms"); + return SHOW_FILL_DIALOG_NO; + } else if (effectiveDuration < mFillDialogMinWaitAfterImeAnimationMs) { + // we need to wait for some time after animation ends + Runnable runnable = createFillDialogEvalRunnable( + response, filledId, filterText, flags); + mHandler.postDelayed(runnable, + mFillDialogMinWaitAfterImeAnimationMs - effectiveDuration); + return SHOW_FILL_DIALOG_WAIT; + } } } + showFillDialog(response, filledId, filterText); + return SHOW_FILL_DIALOG_YES; + } + + private Runnable createFillDialogEvalRunnable( + @NonNull FillResponse response, + @NonNull AutofillId filledId, + String filterText, + int flags) { + return () -> { + synchronized (mLock) { + AutofillValue value = AutofillValue.forText(filterText); + onFillReady(response, filledId, value, flags); + } + }; + } + + private void showFillDialog(FillResponse response, AutofillId filledId, String filterText) { Drawable serviceIcon = null; + PresentationStatsEventLogger logger = null; synchronized (mLock) { serviceIcon = getServiceIcon(response); + logger = mPresentationStatsEventLogger; } - getUiForShowing() - .showFillDialog( - filledId, - response, - filterText, - mService.getServicePackageName(), - mComponentName, - serviceIcon, - this, - id, - mCompatMode, - mPresentationStatsEventLogger, - mLock); - return true; + getUiForShowing().showFillDialog(filledId, response, filterText, + mService.getServicePackageName(), mComponentName, serviceIcon, this, + id, mCompatMode, logger, mLock); } /** @@ -7689,6 +7872,30 @@ final class Session mSessionState = STATE_REMOVED; } + @GuardedBy("mLock") + public void notifyImeAnimationStart(long startTimeMs) { + mImeAnimationStartTimeMs = startTimeMs; + mWaitForImeAnimation = true; + } + + @GuardedBy("mLock") + public void notifyImeAnimationEnd(long endTimeMs) { + mImeAnimationFinishTimeMs = endTimeMs; + // Make sure to use mRunnable with synchronized + if (mFillDialogRunnable != null) { + if (sVerbose) { + Log.v(TAG, "Ime animation ended, starting fill dialog."); + } + mHandler.postDelayed(mFillDialogRunnable, mFillDialogMinWaitAfterImeAnimationMs); + mFillDialogRunnable = null; + } else { + if (sVerbose) { + Log.v(TAG, "Ime animation ended, no runnable present."); + } + } + mWaitForImeAnimation = false; + } + void onPendingSaveUi(int operation, @NonNull IBinder token) { getUiForShowing().onPendingSaveUi(operation, token); } diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java index ffc80ee7d710..7287bdd8e34f 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java @@ -409,5 +409,10 @@ public final class InlineFillUi { * Callback to notify inline ui is hidden. */ void notifyInlineUiHidden(@NonNull AutofillId autofillId); + + /** + * Callback to notify input method started. + */ + void onInputMethodStartInputView(); } } |