OSDN Git Service

autofill: touch on IME should not close autofill
authorDake Gu <dake@google.com>
Mon, 26 Feb 2018 20:25:14 +0000 (12:25 -0800)
committerDake Gu <dake@google.com>
Thu, 1 Mar 2018 00:10:07 +0000 (16:10 -0800)
ag/3434666 causes a regression:
Before ag/3434666, autofill gets touch event after IME, autofill
close itself if it gets ACTION_OUTSIDE touch event.
But after ag/3434666, autofill intercepts touch events before IME, if
user touches within IME, autofill still gets ACTION_OUTSIDE event,
and close itself unexpectedly.

The fix moves the closing code to ViewRootImpl.EarlyPostImeStage
around the same place closing tooltip.

If user taps outside autofill window, we will force to close window,
even last autofillid that requestShowUi does not match.

Bug: 73796497
Test: atest CtsAutoFillServiceTestCases
Test: Added LoginActivityTest.testAutofillTapOutside
Test: manually tested using IME and sample app
TODO: need a fake IME service to dispatch given key upon touch.

Change-Id: I10fc0d29dc30d29a48b2118264ec1c4375062deb

core/java/android/view/ViewRootImpl.java
core/java/android/view/autofill/AutofillManager.java
services/autofill/java/com/android/server/autofill/ui/FillUi.java

index 01d9265..6275566 100644 (file)
@@ -95,6 +95,7 @@ import android.view.accessibility.IAccessibilityInteractionConnection;
 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.Interpolator;
+import android.view.autofill.AutofillManager;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Scroller;
 
@@ -4781,6 +4782,21 @@ public final class ViewRootImpl implements ViewParent,
                 ensureTouchMode(event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN));
             }
 
+            if (action == MotionEvent.ACTION_DOWN && mView instanceof ViewGroup) {
+                // Upon motion event within app window, close autofill ui.
+                ViewGroup decorView = (ViewGroup) mView;
+                if (decorView.getChildCount() > 0) {
+                    // We cannot use decorView's Context for querying AutofillManager: DecorView's
+                    // context is based on Application Context, it would allocate a different
+                    // AutofillManager instance.
+                    AutofillManager afm = (AutofillManager) decorView.getChildAt(0).getContext()
+                            .getSystemService(Context.AUTOFILL_MANAGER_SERVICE);
+                    if (afm != null) {
+                        afm.requestHideFillUi();
+                    }
+                }
+            }
+
             if (action == MotionEvent.ACTION_DOWN && mAttachInfo.mTooltipHost != null) {
                 mAttachInfo.mTooltipHost.hideTooltip();
             }
index a4261eb..1e562ea 100644 (file)
@@ -358,6 +358,9 @@ public final class AutofillManager {
     @GuardedBy("mLock")
     @Nullable private ArraySet<AutofillId> mFillableIds;
 
+    /** id of last requested autofill ui */
+    @Nullable private AutofillId mIdShownFillUi;
+
     /**
      * Views that were already "entered" - if they're entered again when the session is not active,
      * they're ignored
@@ -1547,6 +1550,7 @@ public final class AutofillManager {
         mTrackedViews = null;
         mFillableIds = null;
         mSaveTriggerId = null;
+        mIdShownFillUi = null;
         if (resetEnteredIds) {
             mEnteredIds = null;
         }
@@ -1676,8 +1680,9 @@ public final class AutofillManager {
 
                 if (client != null) {
                     if (client.autofillClientRequestShowFillUi(anchor, width, height,
-                            anchorBounds, presenter) && mCallback != null) {
+                            anchorBounds, presenter)) {
                         callback = mCallback;
+                        mIdShownFillUi = id;
                     }
                 }
             }
@@ -1944,10 +1949,23 @@ public final class AutofillManager {
         }
     }
 
-    private void requestHideFillUi(AutofillId id) {
-        final View anchor = findView(id);
+    /** @hide */
+    public void requestHideFillUi() {
+        requestHideFillUi(mIdShownFillUi, true);
+    }
+
+    private void requestHideFillUi(AutofillId id, boolean force) {
+        final View anchor = id == null ? null : findView(id);
         if (sVerbose) Log.v(TAG, "requestHideFillUi(" + id + "): anchor = " + anchor);
         if (anchor == null) {
+            if (force) {
+                // When user taps outside autofill window, force to close fill ui even id does
+                // not match.
+                AutofillClient client = getClient();
+                if (client != null) {
+                    client.autofillClientRequestHideFillUi();
+                }
+            }
             return;
         }
         requestHideFillUi(id, anchor);
@@ -1963,7 +1981,8 @@ public final class AutofillManager {
             //    service being uninstalled and the UI being dismissed.
             AutofillClient client = getClient();
             if (client != null) {
-                if (client.autofillClientRequestHideFillUi() && mCallback != null) {
+                if (client.autofillClientRequestHideFillUi()) {
+                    mIdShownFillUi = null;
                     callback = mCallback;
                 }
             }
@@ -2655,7 +2674,7 @@ public final class AutofillManager {
         public void requestHideFillUi(int sessionId, AutofillId id) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() -> afm.requestHideFillUi(id));
+                afm.post(() -> afm.requestHideFillUi(id, false));
             }
         }
 
index 7278e83..dbed242 100644 (file)
@@ -590,7 +590,7 @@ final class FillUi {
         }
     }
 
-    final class AnchoredWindow implements View.OnTouchListener {
+    final class AnchoredWindow {
         private final @NonNull OverlayControl mOverlayControl;
         private final WindowManager mWm;
         private final View mContentView;
@@ -623,7 +623,6 @@ final class FillUi {
                     params.accessibilityTitle = mContentView.getContext()
                             .getString(R.string.autofill_picker_accessibility_title);
                     mWm.addView(mContentView, params);
-                    mContentView.setOnTouchListener(this);
                     mOverlayControl.hideOverlays();
                     mShowing = true;
                 } else {
@@ -647,7 +646,6 @@ final class FillUi {
         void hide() {
             try {
                 if (mShowing) {
-                    mContentView.setOnTouchListener(null);
                     mWm.removeView(mContentView);
                     mShowing = false;
                 }
@@ -661,16 +659,6 @@ final class FillUi {
                 mOverlayControl.showOverlays();
             }
         }
-
-        @Override
-        public boolean onTouch(View view, MotionEvent event) {
-            // When the window is touched outside, hide the window.
-            if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-                mCallback.onCanceled();
-                return true;
-            }
-            return false;
-        }
     }
 
     public void dump(PrintWriter pw, String prefix) {