Loading core/java/android/app/Activity.java +52 −7 Original line number Diff line number Diff line Loading @@ -857,6 +857,7 @@ public class Activity extends ContextThemeWrapper private boolean mHasCurrentPermissionsRequest; private boolean mAutoFillResetNeeded; private boolean mAutoFillIgnoreFirstResumePause; /** The last autofill id that was returned from {@link #getNextAutofillId()} */ private int mLastAutofillId = View.LAST_APP_AUTOFILL_ID; Loading Loading @@ -1253,10 +1254,7 @@ public class Activity extends ContextThemeWrapper getApplication().dispatchActivityStarted(this); if (mAutoFillResetNeeded) { AutofillManager afm = getAutofillManager(); if (afm != null) { afm.onVisibleForAutofill(); } getAutofillManager().onVisibleForAutofill(); } } Loading Loading @@ -1320,6 +1318,20 @@ public class Activity extends ContextThemeWrapper if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this); getApplication().dispatchActivityResumed(this); mActivityTransitionState.onResume(this, isTopOfTask()); if (mAutoFillResetNeeded) { if (!mAutoFillIgnoreFirstResumePause) { View focus = getCurrentFocus(); if (focus != null && focus.canNotifyAutofillEnterExitEvent()) { // TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest# // testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial // window visibility after recreation is INVISIBLE in onResume() and next frame // ViewRootImpl.performTraversals() changes window visibility to VISIBLE. // So we cannot call View.notifyEnterOrExited() which will do nothing // when View.isVisibleToUser() is false. getAutofillManager().notifyViewEntered(focus); } } } mCalled = true; } Loading Loading @@ -1681,6 +1693,19 @@ public class Activity extends ContextThemeWrapper protected void onPause() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this); getApplication().dispatchActivityPaused(this); if (mAutoFillResetNeeded) { if (!mAutoFillIgnoreFirstResumePause) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill notifyViewExited " + this); View focus = getCurrentFocus(); if (focus != null && focus.canNotifyAutofillEnterExitEvent()) { getAutofillManager().notifyViewExited(focus); } } else { // reset after first pause() if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill got first pause " + this); mAutoFillIgnoreFirstResumePause = false; } } mCalled = true; } Loading Loading @@ -1871,6 +1896,10 @@ public class Activity extends ContextThemeWrapper mTranslucentCallback = null; mCalled = true; if (mAutoFillResetNeeded) { getAutofillManager().onInvisibleForAutofill(); } if (isFinishing()) { if (mAutoFillResetNeeded) { getAutofillManager().onActivityFinished(); Loading Loading @@ -6266,7 +6295,7 @@ public class Activity extends ContextThemeWrapper mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix); final AutofillManager afm = getAutofillManager(); final AutofillManager afm = mAutofillManager; if (afm != null) { afm.dump(prefix, writer); } else { Loading Loading @@ -7119,13 +7148,23 @@ public class Activity extends ContextThemeWrapper } } final void performResume() { final void performResume(boolean followedByPause) { performRestart(true /* start */); mFragments.execPendingActions(); mLastNonConfigurationInstances = null; if (mAutoFillResetNeeded) { // When Activity is destroyed in paused state, and relaunch activity, there will be // extra onResume and onPause event, ignore the first onResume and onPause. // see ActivityThread.handleRelaunchActivity() mAutoFillIgnoreFirstResumePause = followedByPause; if (mAutoFillIgnoreFirstResumePause && DEBUG_LIFECYCLE) { Slog.v(TAG, "autofill will ignore first pause when relaunching " + this); } } mCalled = false; // mResumed is set by the instrumentation mInstrumentation.callActivityOnResume(this); Loading Loading @@ -7310,7 +7349,7 @@ public class Activity extends ContextThemeWrapper } } else if (who.startsWith(AUTO_FILL_AUTH_WHO_PREFIX)) { Intent resultData = (resultCode == Activity.RESULT_OK) ? data : null; getAutofillManager().onAuthenticationResult(requestCode, resultData); getAutofillManager().onAuthenticationResult(requestCode, resultData, getCurrentFocus()); } else { Fragment frag = mFragments.findFragmentByWho(who); if (frag != null) { Loading Loading @@ -7584,6 +7623,12 @@ public class Activity extends ContextThemeWrapper return !mStopped; } /** @hide */ @Override public boolean isDisablingEnterExitEventForAutofill() { return mAutoFillIgnoreFirstResumePause || !mResumed; } /** * If set to true, this indicates to the system that it should never take a * screenshot of the activity to be used as a representation while it is not in a started state. Loading core/java/android/app/ActivityThread.java +3 −3 Original line number Diff line number Diff line Loading @@ -3096,7 +3096,7 @@ public final class ActivityThread extends ClientTransactionHandler { checkAndBlockForNetworkAccess(); deliverNewIntents(r, intents); if (resumed) { r.activity.performResume(); r.activity.performResume(false); r.activity.mTemporaryPause = false; } Loading Loading @@ -3718,7 +3718,7 @@ public final class ActivityThread extends ClientTransactionHandler { deliverResults(r, r.pendingResults); r.pendingResults = null; } r.activity.performResume(); r.activity.performResume(r.startsNotResumed); synchronized (mResourcesManager) { // If there is a pending local relaunch that was requested when the activity was Loading Loading @@ -4437,7 +4437,7 @@ public final class ActivityThread extends ClientTransactionHandler { checkAndBlockForNetworkAccess(); deliverResults(r, results); if (resumed) { r.activity.performResume(); r.activity.performResume(false); r.activity.mTemporaryPause = false; } } Loading core/java/android/view/View.java +13 −6 Original line number Diff line number Diff line Loading @@ -7232,20 +7232,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyEnterOrExitForAutoFillIfNeeded(gainFocus); } private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { if (isAutofillable() && isAttachedToWindow()) { /** @hide */ public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { if (canNotifyAutofillEnterExitEvent()) { AutofillManager afm = getAutofillManager(); if (afm != null) { if (enter && hasWindowFocus() && isFocused()) { if (enter && isFocused()) { // We have not been laid out yet, hence cannot evaluate // whether this view is visible to the user, we will do // the evaluation once layout is complete. if (!isLaidOut()) { mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; } else if (isVisibleToUser()) { // TODO This is a potential problem that View gets focus before it's visible // to User. Ideally View should handle the event when isVisibleToUser() // becomes true where it should issue notifyViewEntered(). afm.notifyViewEntered(this); } } else if (!hasWindowFocus() || !isFocused()) { } else if (!isFocused()) { afm.notifyViewExited(this); } } Loading Loading @@ -8317,6 +8321,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, && getAutofillViewId() > LAST_APP_AUTOFILL_ID; } /** @hide */ public boolean canNotifyAutofillEnterExitEvent() { return isAutofillable() && isAttachedToWindow(); } private void populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), Loading Loading @@ -12451,8 +12460,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, imm.focusIn(this); } notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); refreshDrawableState(); } core/java/android/view/autofill/AutofillManager.java +121 −36 Original line number Diff line number Diff line Loading @@ -341,6 +341,10 @@ public final class AutofillManager { @GuardedBy("mLock") @Nullable private AutofillId mSaveTriggerId; /** set to true when onInvisibleForAutofill is called, used by onAuthenticationResult */ @GuardedBy("mLock") private boolean mOnInvisibleCalled; /** If set, session is commited when the activity is finished; otherwise session is canceled. */ @GuardedBy("mLock") private boolean mSaveOnFinish; Loading Loading @@ -396,6 +400,11 @@ public final class AutofillManager { */ boolean isVisibleForAutofill(); /** * Client might disable enter/exit event e.g. when activity is paused. */ boolean isDisablingEnterExitEventForAutofill(); /** * Finds views by traversing the hierarchies of the client. * Loading Loading @@ -498,6 +507,19 @@ public final class AutofillManager { } } /** * Called once the client becomes invisible. * * @see AutofillClient#isVisibleForAutofill() * * {@hide} */ public void onInvisibleForAutofill() { synchronized (mLock) { mOnInvisibleCalled = true; } } /** * Save state before activity lifecycle * Loading Loading @@ -623,13 +645,35 @@ public final class AutofillManager { return false; } private boolean isClientVisibleForAutofillLocked() { final AutofillClient client = getClient(); return client != null && client.isVisibleForAutofill(); } private boolean isClientDisablingEnterExitEvent() { final AutofillClient client = getClient(); return client != null && client.isDisablingEnterExitEventForAutofill(); } private void notifyViewEntered(@NonNull View view, int flags) { if (!hasAutofillFeature()) { return; } AutofillCallback callback = null; AutofillCallback callback; synchronized (mLock) { if (shouldIgnoreViewEnteredLocked(view, flags)) return; callback = notifyViewEnteredLocked(view, flags); } if (callback != null) { mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } } /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */ private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) { if (shouldIgnoreViewEnteredLocked(view, flags)) return null; AutofillCallback callback = null; ensureServiceClientAddedIfNeededLocked(); Loading @@ -638,6 +682,8 @@ public final class AutofillManager { callback = mCallback; } } else { // don't notify entered when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view); final AutofillValue value = view.getAutofillValue(); Loading @@ -650,10 +696,7 @@ public final class AutofillManager { } } } if (callback != null) { mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } return callback; } /** Loading @@ -666,9 +709,16 @@ public final class AutofillManager { return; } synchronized (mLock) { notifyViewExitedLocked(view); } } void notifyViewExitedLocked(@NonNull View view) { ensureServiceClientAddedIfNeededLocked(); if (mEnabled && isActiveLocked()) { // dont notify exited when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view); // Update focus on existing session. Loading Loading @@ -719,7 +769,7 @@ public final class AutofillManager { } } if (mTrackedViews != null) { mTrackedViews.notifyViewVisibilityChanged(id, isVisible); mTrackedViews.notifyViewVisibilityChangedLocked(id, isVisible); } } } Loading Loading @@ -752,9 +802,22 @@ public final class AutofillManager { if (!hasAutofillFeature()) { return; } AutofillCallback callback = null; AutofillCallback callback; synchronized (mLock) { if (shouldIgnoreViewEnteredLocked(view, flags)) return; callback = notifyViewEnteredLocked(view, virtualId, bounds, flags); } if (callback != null) { callback.onAutofillEvent(view, virtualId, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } } /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */ private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds, int flags) { AutofillCallback callback = null; if (shouldIgnoreViewEnteredLocked(view, flags)) return callback; ensureServiceClientAddedIfNeededLocked(); Loading @@ -763,6 +826,8 @@ public final class AutofillManager { callback = mCallback; } } else { // don't notify entered when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view, virtualId); if (!isActiveLocked()) { Loading @@ -774,11 +839,7 @@ public final class AutofillManager { } } } if (callback != null) { callback.onAutofillEvent(view, virtualId, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } return callback; } /** Loading @@ -792,9 +853,16 @@ public final class AutofillManager { return; } synchronized (mLock) { notifyViewExitedLocked(view, virtualId); } } private void notifyViewExitedLocked(@NonNull View view, int virtualId) { ensureServiceClientAddedIfNeededLocked(); if (mEnabled && isActiveLocked()) { // don't notify exited when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view, virtualId); // Update focus on existing session. Loading Loading @@ -1155,7 +1223,7 @@ public final class AutofillManager { } /** @hide */ public void onAuthenticationResult(int authenticationId, Intent data) { public void onAuthenticationResult(int authenticationId, Intent data, View focusView) { if (!hasAutofillFeature()) { return; } Loading @@ -1167,9 +1235,24 @@ public final class AutofillManager { if (sDebug) Log.d(TAG, "onAuthenticationResult(): d=" + data); synchronized (mLock) { if (!isActiveLocked() || data == null) { if (!isActiveLocked()) { return; } // If authenticate activity closes itself during onCreate(), there is no onStop/onStart // of app activity. We enforce enter event to re-show fill ui in such case. // CTS example: // LoginActivityTest#testDatasetAuthTwoFieldsUserCancelsFirstAttempt // LoginActivityTest#testFillResponseAuthBothFieldsUserCancelsFirstAttempt if (!mOnInvisibleCalled && focusView != null && focusView.canNotifyAutofillEnterExitEvent()) { notifyViewExitedLocked(focusView); notifyViewEnteredLocked(focusView, 0); } if (data == null) { // data is set to null when result is not RESULT_OK return; } final Parcelable result = data.getParcelableExtra(EXTRA_AUTHENTICATION_RESULT); final Bundle responseData = new Bundle(); responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result); Loading Loading @@ -1402,6 +1485,9 @@ public final class AutofillManager { if (sessionId == mSessionId) { final AutofillClient client = getClient(); if (client != null) { // clear mOnInvisibleCalled and we will see if receive onInvisibleForAutofill() // before onAuthenticationResult() mOnInvisibleCalled = false; client.autofillCallbackAuthenticate(authenticationId, intent, fillInIntent); } } Loading Loading @@ -1767,6 +1853,7 @@ public final class AutofillManager { pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled); pw.print(pfx); pw.print("hasService: "); pw.println(mService != null); pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null); pw.print(pfx); pw.print("onInvisibleCalled "); pw.println(mOnInvisibleCalled); pw.print(pfx); pw.print("last autofilled data: "); pw.println(mLastAutofilledData); pw.print(pfx); pw.print("tracked views: "); if (mTrackedViews == null) { Loading Loading @@ -1937,15 +2024,13 @@ public final class AutofillManager { * @param id the id of the view/virtual view whose visibility changed. * @param isVisible visible if the view is visible in the view hierarchy. */ void notifyViewVisibilityChanged(@NonNull AutofillId id, boolean isVisible) { AutofillClient client = getClient(); void notifyViewVisibilityChangedLocked(@NonNull AutofillId id, boolean isVisible) { if (sDebug) { Log.d(TAG, "notifyViewVisibilityChanged(): id=" + id + " isVisible=" + isVisible); } if (client != null && client.isVisibleForAutofill()) { if (isClientVisibleForAutofillLocked()) { if (isVisible) { if (isInSet(mInvisibleTrackedIds, id)) { mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id); Loading core/java/android/view/autofill/AutofillPopupWindow.java +3 −1 Original line number Diff line number Diff line Loading @@ -78,8 +78,10 @@ public class AutofillPopupWindow extends PopupWindow { public AutofillPopupWindow(@NonNull IAutofillWindowPresenter presenter) { mWindowPresenter = new WindowPresenter(presenter); setTouchModal(false); setOutsideTouchable(true); setInputMethodMode(INPUT_METHOD_NEEDED); setInputMethodMode(INPUT_METHOD_NOT_NEEDED); setFocusable(true); } @Override Loading Loading
core/java/android/app/Activity.java +52 −7 Original line number Diff line number Diff line Loading @@ -857,6 +857,7 @@ public class Activity extends ContextThemeWrapper private boolean mHasCurrentPermissionsRequest; private boolean mAutoFillResetNeeded; private boolean mAutoFillIgnoreFirstResumePause; /** The last autofill id that was returned from {@link #getNextAutofillId()} */ private int mLastAutofillId = View.LAST_APP_AUTOFILL_ID; Loading Loading @@ -1253,10 +1254,7 @@ public class Activity extends ContextThemeWrapper getApplication().dispatchActivityStarted(this); if (mAutoFillResetNeeded) { AutofillManager afm = getAutofillManager(); if (afm != null) { afm.onVisibleForAutofill(); } getAutofillManager().onVisibleForAutofill(); } } Loading Loading @@ -1320,6 +1318,20 @@ public class Activity extends ContextThemeWrapper if (DEBUG_LIFECYCLE) Slog.v(TAG, "onResume " + this); getApplication().dispatchActivityResumed(this); mActivityTransitionState.onResume(this, isTopOfTask()); if (mAutoFillResetNeeded) { if (!mAutoFillIgnoreFirstResumePause) { View focus = getCurrentFocus(); if (focus != null && focus.canNotifyAutofillEnterExitEvent()) { // TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest# // testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial // window visibility after recreation is INVISIBLE in onResume() and next frame // ViewRootImpl.performTraversals() changes window visibility to VISIBLE. // So we cannot call View.notifyEnterOrExited() which will do nothing // when View.isVisibleToUser() is false. getAutofillManager().notifyViewEntered(focus); } } } mCalled = true; } Loading Loading @@ -1681,6 +1693,19 @@ public class Activity extends ContextThemeWrapper protected void onPause() { if (DEBUG_LIFECYCLE) Slog.v(TAG, "onPause " + this); getApplication().dispatchActivityPaused(this); if (mAutoFillResetNeeded) { if (!mAutoFillIgnoreFirstResumePause) { if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill notifyViewExited " + this); View focus = getCurrentFocus(); if (focus != null && focus.canNotifyAutofillEnterExitEvent()) { getAutofillManager().notifyViewExited(focus); } } else { // reset after first pause() if (DEBUG_LIFECYCLE) Slog.v(TAG, "autofill got first pause " + this); mAutoFillIgnoreFirstResumePause = false; } } mCalled = true; } Loading Loading @@ -1871,6 +1896,10 @@ public class Activity extends ContextThemeWrapper mTranslucentCallback = null; mCalled = true; if (mAutoFillResetNeeded) { getAutofillManager().onInvisibleForAutofill(); } if (isFinishing()) { if (mAutoFillResetNeeded) { getAutofillManager().onActivityFinished(); Loading Loading @@ -6266,7 +6295,7 @@ public class Activity extends ContextThemeWrapper mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix); final AutofillManager afm = getAutofillManager(); final AutofillManager afm = mAutofillManager; if (afm != null) { afm.dump(prefix, writer); } else { Loading Loading @@ -7119,13 +7148,23 @@ public class Activity extends ContextThemeWrapper } } final void performResume() { final void performResume(boolean followedByPause) { performRestart(true /* start */); mFragments.execPendingActions(); mLastNonConfigurationInstances = null; if (mAutoFillResetNeeded) { // When Activity is destroyed in paused state, and relaunch activity, there will be // extra onResume and onPause event, ignore the first onResume and onPause. // see ActivityThread.handleRelaunchActivity() mAutoFillIgnoreFirstResumePause = followedByPause; if (mAutoFillIgnoreFirstResumePause && DEBUG_LIFECYCLE) { Slog.v(TAG, "autofill will ignore first pause when relaunching " + this); } } mCalled = false; // mResumed is set by the instrumentation mInstrumentation.callActivityOnResume(this); Loading Loading @@ -7310,7 +7349,7 @@ public class Activity extends ContextThemeWrapper } } else if (who.startsWith(AUTO_FILL_AUTH_WHO_PREFIX)) { Intent resultData = (resultCode == Activity.RESULT_OK) ? data : null; getAutofillManager().onAuthenticationResult(requestCode, resultData); getAutofillManager().onAuthenticationResult(requestCode, resultData, getCurrentFocus()); } else { Fragment frag = mFragments.findFragmentByWho(who); if (frag != null) { Loading Loading @@ -7584,6 +7623,12 @@ public class Activity extends ContextThemeWrapper return !mStopped; } /** @hide */ @Override public boolean isDisablingEnterExitEventForAutofill() { return mAutoFillIgnoreFirstResumePause || !mResumed; } /** * If set to true, this indicates to the system that it should never take a * screenshot of the activity to be used as a representation while it is not in a started state. Loading
core/java/android/app/ActivityThread.java +3 −3 Original line number Diff line number Diff line Loading @@ -3096,7 +3096,7 @@ public final class ActivityThread extends ClientTransactionHandler { checkAndBlockForNetworkAccess(); deliverNewIntents(r, intents); if (resumed) { r.activity.performResume(); r.activity.performResume(false); r.activity.mTemporaryPause = false; } Loading Loading @@ -3718,7 +3718,7 @@ public final class ActivityThread extends ClientTransactionHandler { deliverResults(r, r.pendingResults); r.pendingResults = null; } r.activity.performResume(); r.activity.performResume(r.startsNotResumed); synchronized (mResourcesManager) { // If there is a pending local relaunch that was requested when the activity was Loading Loading @@ -4437,7 +4437,7 @@ public final class ActivityThread extends ClientTransactionHandler { checkAndBlockForNetworkAccess(); deliverResults(r, results); if (resumed) { r.activity.performResume(); r.activity.performResume(false); r.activity.mTemporaryPause = false; } } Loading
core/java/android/view/View.java +13 −6 Original line number Diff line number Diff line Loading @@ -7232,20 +7232,24 @@ public class View implements Drawable.Callback, KeyEvent.Callback, notifyEnterOrExitForAutoFillIfNeeded(gainFocus); } private void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { if (isAutofillable() && isAttachedToWindow()) { /** @hide */ public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { if (canNotifyAutofillEnterExitEvent()) { AutofillManager afm = getAutofillManager(); if (afm != null) { if (enter && hasWindowFocus() && isFocused()) { if (enter && isFocused()) { // We have not been laid out yet, hence cannot evaluate // whether this view is visible to the user, we will do // the evaluation once layout is complete. if (!isLaidOut()) { mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; } else if (isVisibleToUser()) { // TODO This is a potential problem that View gets focus before it's visible // to User. Ideally View should handle the event when isVisibleToUser() // becomes true where it should issue notifyViewEntered(). afm.notifyViewEntered(this); } } else if (!hasWindowFocus() || !isFocused()) { } else if (!isFocused()) { afm.notifyViewExited(this); } } Loading Loading @@ -8317,6 +8321,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, && getAutofillViewId() > LAST_APP_AUTOFILL_ID; } /** @hide */ public boolean canNotifyAutofillEnterExitEvent() { return isAutofillable() && isAttachedToWindow(); } private void populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), Loading Loading @@ -12451,8 +12460,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, imm.focusIn(this); } notifyEnterOrExitForAutoFillIfNeeded(hasWindowFocus); refreshDrawableState(); }
core/java/android/view/autofill/AutofillManager.java +121 −36 Original line number Diff line number Diff line Loading @@ -341,6 +341,10 @@ public final class AutofillManager { @GuardedBy("mLock") @Nullable private AutofillId mSaveTriggerId; /** set to true when onInvisibleForAutofill is called, used by onAuthenticationResult */ @GuardedBy("mLock") private boolean mOnInvisibleCalled; /** If set, session is commited when the activity is finished; otherwise session is canceled. */ @GuardedBy("mLock") private boolean mSaveOnFinish; Loading Loading @@ -396,6 +400,11 @@ public final class AutofillManager { */ boolean isVisibleForAutofill(); /** * Client might disable enter/exit event e.g. when activity is paused. */ boolean isDisablingEnterExitEventForAutofill(); /** * Finds views by traversing the hierarchies of the client. * Loading Loading @@ -498,6 +507,19 @@ public final class AutofillManager { } } /** * Called once the client becomes invisible. * * @see AutofillClient#isVisibleForAutofill() * * {@hide} */ public void onInvisibleForAutofill() { synchronized (mLock) { mOnInvisibleCalled = true; } } /** * Save state before activity lifecycle * Loading Loading @@ -623,13 +645,35 @@ public final class AutofillManager { return false; } private boolean isClientVisibleForAutofillLocked() { final AutofillClient client = getClient(); return client != null && client.isVisibleForAutofill(); } private boolean isClientDisablingEnterExitEvent() { final AutofillClient client = getClient(); return client != null && client.isDisablingEnterExitEventForAutofill(); } private void notifyViewEntered(@NonNull View view, int flags) { if (!hasAutofillFeature()) { return; } AutofillCallback callback = null; AutofillCallback callback; synchronized (mLock) { if (shouldIgnoreViewEnteredLocked(view, flags)) return; callback = notifyViewEnteredLocked(view, flags); } if (callback != null) { mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } } /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */ private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) { if (shouldIgnoreViewEnteredLocked(view, flags)) return null; AutofillCallback callback = null; ensureServiceClientAddedIfNeededLocked(); Loading @@ -638,6 +682,8 @@ public final class AutofillManager { callback = mCallback; } } else { // don't notify entered when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view); final AutofillValue value = view.getAutofillValue(); Loading @@ -650,10 +696,7 @@ public final class AutofillManager { } } } if (callback != null) { mCallback.onAutofillEvent(view, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } return callback; } /** Loading @@ -666,9 +709,16 @@ public final class AutofillManager { return; } synchronized (mLock) { notifyViewExitedLocked(view); } } void notifyViewExitedLocked(@NonNull View view) { ensureServiceClientAddedIfNeededLocked(); if (mEnabled && isActiveLocked()) { // dont notify exited when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view); // Update focus on existing session. Loading Loading @@ -719,7 +769,7 @@ public final class AutofillManager { } } if (mTrackedViews != null) { mTrackedViews.notifyViewVisibilityChanged(id, isVisible); mTrackedViews.notifyViewVisibilityChangedLocked(id, isVisible); } } } Loading Loading @@ -752,9 +802,22 @@ public final class AutofillManager { if (!hasAutofillFeature()) { return; } AutofillCallback callback = null; AutofillCallback callback; synchronized (mLock) { if (shouldIgnoreViewEnteredLocked(view, flags)) return; callback = notifyViewEnteredLocked(view, virtualId, bounds, flags); } if (callback != null) { callback.onAutofillEvent(view, virtualId, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } } /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */ private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds, int flags) { AutofillCallback callback = null; if (shouldIgnoreViewEnteredLocked(view, flags)) return callback; ensureServiceClientAddedIfNeededLocked(); Loading @@ -763,6 +826,8 @@ public final class AutofillManager { callback = mCallback; } } else { // don't notify entered when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view, virtualId); if (!isActiveLocked()) { Loading @@ -774,11 +839,7 @@ public final class AutofillManager { } } } if (callback != null) { callback.onAutofillEvent(view, virtualId, AutofillCallback.EVENT_INPUT_UNAVAILABLE); } return callback; } /** Loading @@ -792,9 +853,16 @@ public final class AutofillManager { return; } synchronized (mLock) { notifyViewExitedLocked(view, virtualId); } } private void notifyViewExitedLocked(@NonNull View view, int virtualId) { ensureServiceClientAddedIfNeededLocked(); if (mEnabled && isActiveLocked()) { // don't notify exited when Activity is already in background if (!isClientDisablingEnterExitEvent()) { final AutofillId id = getAutofillId(view, virtualId); // Update focus on existing session. Loading Loading @@ -1155,7 +1223,7 @@ public final class AutofillManager { } /** @hide */ public void onAuthenticationResult(int authenticationId, Intent data) { public void onAuthenticationResult(int authenticationId, Intent data, View focusView) { if (!hasAutofillFeature()) { return; } Loading @@ -1167,9 +1235,24 @@ public final class AutofillManager { if (sDebug) Log.d(TAG, "onAuthenticationResult(): d=" + data); synchronized (mLock) { if (!isActiveLocked() || data == null) { if (!isActiveLocked()) { return; } // If authenticate activity closes itself during onCreate(), there is no onStop/onStart // of app activity. We enforce enter event to re-show fill ui in such case. // CTS example: // LoginActivityTest#testDatasetAuthTwoFieldsUserCancelsFirstAttempt // LoginActivityTest#testFillResponseAuthBothFieldsUserCancelsFirstAttempt if (!mOnInvisibleCalled && focusView != null && focusView.canNotifyAutofillEnterExitEvent()) { notifyViewExitedLocked(focusView); notifyViewEnteredLocked(focusView, 0); } if (data == null) { // data is set to null when result is not RESULT_OK return; } final Parcelable result = data.getParcelableExtra(EXTRA_AUTHENTICATION_RESULT); final Bundle responseData = new Bundle(); responseData.putParcelable(EXTRA_AUTHENTICATION_RESULT, result); Loading Loading @@ -1402,6 +1485,9 @@ public final class AutofillManager { if (sessionId == mSessionId) { final AutofillClient client = getClient(); if (client != null) { // clear mOnInvisibleCalled and we will see if receive onInvisibleForAutofill() // before onAuthenticationResult() mOnInvisibleCalled = false; client.autofillCallbackAuthenticate(authenticationId, intent, fillInIntent); } } Loading Loading @@ -1767,6 +1853,7 @@ public final class AutofillManager { pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled); pw.print(pfx); pw.print("hasService: "); pw.println(mService != null); pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null); pw.print(pfx); pw.print("onInvisibleCalled "); pw.println(mOnInvisibleCalled); pw.print(pfx); pw.print("last autofilled data: "); pw.println(mLastAutofilledData); pw.print(pfx); pw.print("tracked views: "); if (mTrackedViews == null) { Loading Loading @@ -1937,15 +2024,13 @@ public final class AutofillManager { * @param id the id of the view/virtual view whose visibility changed. * @param isVisible visible if the view is visible in the view hierarchy. */ void notifyViewVisibilityChanged(@NonNull AutofillId id, boolean isVisible) { AutofillClient client = getClient(); void notifyViewVisibilityChangedLocked(@NonNull AutofillId id, boolean isVisible) { if (sDebug) { Log.d(TAG, "notifyViewVisibilityChanged(): id=" + id + " isVisible=" + isVisible); } if (client != null && client.isVisibleForAutofill()) { if (isClientVisibleForAutofillLocked()) { if (isVisible) { if (isInSet(mInvisibleTrackedIds, id)) { mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id); Loading
core/java/android/view/autofill/AutofillPopupWindow.java +3 −1 Original line number Diff line number Diff line Loading @@ -78,8 +78,10 @@ public class AutofillPopupWindow extends PopupWindow { public AutofillPopupWindow(@NonNull IAutofillWindowPresenter presenter) { mWindowPresenter = new WindowPresenter(presenter); setTouchModal(false); setOutsideTouchable(true); setInputMethodMode(INPUT_METHOD_NEEDED); setInputMethodMode(INPUT_METHOD_NOT_NEEDED); setFocusable(true); } @Override Loading