From 374cae1e61ee1f9f3e4dbe937e4c643466ed031d Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Wed, 10 May 2017 13:42:33 -0700 Subject: [PATCH] Properly position dataset picker UI Test: all autofill CTS tests pass bug:37958210 bug:37986800 Change-Id: Ic2cb3b8c6762a922bdb7c632e451772b7a006739 --- core/java/android/app/Activity.java | 11 +-- .../view/autofill/AutofillPopupWindow.java | 93 +++++++++++++++++-- 2 files changed, 86 insertions(+), 18 deletions(-) diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index ad272b8b83b33..6fa0a6daeca01 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -7439,14 +7439,6 @@ public class Activity extends ContextThemeWrapper @Override final public boolean autofillCallbackRequestShowFillUi(@NonNull View anchor, int width, int height, @Nullable Rect anchorBounds, IAutofillWindowPresenter presenter) { - final Rect actualAnchorBounds = new Rect(); - anchor.getBoundsOnScreen(actualAnchorBounds); - - final int offsetX = (anchorBounds != null) - ? anchorBounds.left - actualAnchorBounds.left : 0; - int offsetY = (anchorBounds != null) - ? anchorBounds.top - actualAnchorBounds.top : 0; - final boolean wasShowing; if (mAutofillPopupWindow == null) { @@ -7455,8 +7447,7 @@ public class Activity extends ContextThemeWrapper } else { wasShowing = mAutofillPopupWindow.isShowing(); } - mAutofillPopupWindow.update(anchor, offsetX, offsetY, width, height, anchorBounds, - actualAnchorBounds); + mAutofillPopupWindow.update(anchor, 0, 0, width, height, anchorBounds); return !wasShowing && mAutofillPopupWindow.isShowing(); } diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java index 056e540d3bb30..cd16a245c9b46 100644 --- a/core/java/android/view/autofill/AutofillPopupWindow.java +++ b/core/java/android/view/autofill/AutofillPopupWindow.java @@ -19,11 +19,13 @@ package android.view.autofill; import android.annotation.NonNull; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.IBinder; import android.os.RemoteException; import android.transition.Transition; import android.util.Log; import android.view.View; import android.view.View.OnTouchListener; +import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.PopupWindow; @@ -84,18 +86,93 @@ public class AutofillPopupWindow extends PopupWindow { * The effective {@code update} method that should be called by its clients. */ public void update(View anchor, int offsetX, int offsetY, int width, int height, - Rect anchorBounds, Rect actualAnchorBounds) { + Rect virtualBounds) { + // If we are showing the popup for a virtual view we use a fake view which + // delegates to the anchor but present itself with the same bounds as the + // virtual view. This ensures that the location logic in popup works + // symmetrically when the dropdown is below and above the anchor. + final View actualAnchor; + if (virtualBounds != null) { + actualAnchor = new View(anchor.getContext()) { + @Override + public void getLocationOnScreen(int[] location) { + location[0] = virtualBounds.left; + location[1] = virtualBounds.top; + } + + @Override + public int getAccessibilityViewId() { + return anchor.getAccessibilityViewId(); + } + + @Override + public ViewTreeObserver getViewTreeObserver() { + return anchor.getViewTreeObserver(); + } + + @Override + public IBinder getApplicationWindowToken() { + return anchor.getApplicationWindowToken(); + } + + @Override + public View getRootView() { + return anchor.getRootView(); + } + + @Override + public int getLayoutDirection() { + return anchor.getLayoutDirection(); + } + + @Override + public void getWindowDisplayFrame(Rect outRect) { + anchor.getWindowDisplayFrame(outRect); + } + + @Override + public void addOnAttachStateChangeListener( + OnAttachStateChangeListener listener) { + anchor.addOnAttachStateChangeListener(listener); + } + + @Override + public void removeOnAttachStateChangeListener( + OnAttachStateChangeListener listener) { + anchor.removeOnAttachStateChangeListener(listener); + } + + @Override + public boolean isAttachedToWindow() { + return anchor.isAttachedToWindow(); + } + + @Override + public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { + return anchor.requestRectangleOnScreen(rectangle, immediate); + } + + @Override + public IBinder getWindowToken() { + return anchor.getWindowToken(); + } + }; + + actualAnchor.setLeftTopRightBottom( + virtualBounds.left, virtualBounds.top, + virtualBounds.right, virtualBounds.bottom); + actualAnchor.setScrollX(anchor.getScrollX()); + actualAnchor.setScrollY(anchor.getScrollY()); + } else { + actualAnchor = anchor; + } + if (!isShowing()) { setWidth(width); setHeight(height); - showAsDropDown(anchor, offsetX, offsetY); + showAsDropDown(actualAnchor, offsetX, offsetY); } else { - update(anchor, offsetX, offsetY, width, height); - } - - if (anchorBounds != null && mWindowLayoutParams.y > anchorBounds.bottom) { - offsetY = anchorBounds.bottom - actualAnchorBounds.bottom; - update(anchor, offsetX, offsetY, width, height); + update(actualAnchor, offsetX, offsetY, width, height); } }