Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4a2f9857 authored by Alan Viverette's avatar Alan Viverette Committed by Android (Google) Code Review
Browse files

Merge "Ensure correct width and height are used during popup positioning" into nyc-dev

parents 363e70dd f50df436
Loading
Loading
Loading
Loading
+85 −77
Original line number Diff line number Diff line
@@ -129,8 +129,8 @@ public class PopupWindow {
     */
    private static final int ANIMATION_STYLE_DEFAULT = -1;

    private final int[] mDrawingLocation = new int[2];
    private final int[] mScreenLocation = new int[2];
    private final int[] mTmpDrawingLocation = new int[2];
    private final int[] mTmpScreenLocation = new int[2];
    private final Rect mTempRect = new Rect();

    private Context mContext;
@@ -222,7 +222,7 @@ public class PopupWindow {
                        mDecorView.getLayoutParams();

                updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
                        mAnchoredGravity));
                        p.width, p.height, mAnchoredGravity));
                update(p.x, p.y, -1, -1, true);
            }
        }
@@ -1123,7 +1123,7 @@ public class PopupWindow {

        TransitionManager.endTransitions(mDecorView);

        unregisterForViewTreeChanges();
        detachFromAnchor();

        mIsShowing = true;
        mIsDropdown = false;
@@ -1206,7 +1206,7 @@ public class PopupWindow {

        TransitionManager.endTransitions(mDecorView);

        registerForViewTreeChanges(anchor, xoff, yoff, gravity);
        attachToAnchor(anchor, xoff, yoff, gravity);

        mIsShowing = true;
        mIsDropdown = true;
@@ -1214,7 +1214,8 @@ public class PopupWindow {
        final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken());
        preparePopup(p);

        final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, gravity);
        final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff,
                p.width, p.height, gravity);
        updateAboveAnchor(aboveAnchor);

        invokePopup(p);
@@ -1494,120 +1495,130 @@ public class PopupWindow {
     * to reclaim space. If scrolling is not possible or not enough, the popup
     * window gets moved on top of the anchor.
     * <p>
     * The height must have been set on the layout parameters prior to calling
     * this method.
     * The results of positioning are placed in {@code outParams}.
     *
     * @param anchor the view on which the popup window must be anchored
     * @param p the layout parameters used to display the drop down
     * @param xoff horizontal offset used to adjust for background padding
     * @param yoff vertical offset used to adjust for background padding
     * @param outParams the layout parameters used to display the drop down
     * @param xOffset horizontal offset used to adjust for background padding
     * @param yOffset vertical offset used to adjust for background padding
     * @param gravity horizontal gravity specifying popup alignment
     * @return true if the popup is translated upwards to fit on screen
     */
    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams p, int xoff,
            int yoff, int gravity) {
    private boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
            int xOffset, int yOffset, int width, int height, int gravity) {
        final int anchorHeight = anchor.getHeight();
        final int anchorWidth = anchor.getWidth();
        if (mOverlapAnchor) {
            yoff -= anchorHeight;
            yOffset -= anchorHeight;
        }

        anchor.getLocationInWindow(mDrawingLocation);
        p.x = mDrawingLocation[0] + xoff;
        p.y = mDrawingLocation[1] + anchorHeight + yoff;
        final int[] drawingLocation = mTmpDrawingLocation;
        anchor.getLocationInWindow(drawingLocation);
        outParams.x = drawingLocation[0] + xOffset;
        outParams.y = drawingLocation[1] + anchorHeight + yOffset;

        final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
                & Gravity.HORIZONTAL_GRAVITY_MASK;
        if (hgrav == Gravity.RIGHT) {
            // Flip the location to align the right sides of the popup and
            // anchor instead of left.
            p.x -= mPopupWidth - anchorWidth;
            outParams.x -= width - anchorWidth;
        }

        boolean onTop = false;
        outParams.gravity = Gravity.LEFT | Gravity.TOP;

        p.gravity = Gravity.LEFT | Gravity.TOP;
        final int[] screenLocation = mTmpScreenLocation;
        anchor.getLocationOnScreen(screenLocation);

        anchor.getLocationOnScreen(mScreenLocation);
        final Rect displayFrame = new Rect();
        anchor.getWindowVisibleDisplayFrame(displayFrame);

        final int screenY = mScreenLocation[1] + anchorHeight + yoff;
        final boolean onTop;
        final int screenY = screenLocation[1] + anchorHeight + yOffset;
        final View root = anchor.getRootView();
        if (screenY + mPopupHeight > displayFrame.bottom
                || p.x + mPopupWidth - root.getWidth() > 0) {
        if (screenY + height > displayFrame.bottom
                || outParams.x + width - root.getWidth() > 0) {
            // If the drop down disappears at the bottom of the screen, we try
            // to scroll a parent scrollview or move the drop down back up on
            // top of the edit box.
            if (mAllowScrollingAnchorParent) {
                final int scrollX = anchor.getScrollX();
                final int scrollY = anchor.getScrollY();
                final Rect r = new Rect(scrollX, scrollY, scrollX + mPopupWidth + xoff,
                        scrollY + mPopupHeight + anchorHeight + yoff);
                final Rect r = new Rect(scrollX, scrollY, scrollX + width + xOffset,
                        scrollY + height + anchorHeight + yOffset);
                anchor.requestRectangleOnScreen(r, true);
            }

            // Now we re-evaluate the space available, and decide from that
            // whether the pop-up will go above or below the anchor.
            anchor.getLocationInWindow(mDrawingLocation);
            p.x = mDrawingLocation[0] + xoff;
            p.y = mDrawingLocation[1] + anchorHeight + yoff;
            anchor.getLocationInWindow(drawingLocation);
            outParams.x = drawingLocation[0] + xOffset;
            outParams.y = drawingLocation[1] + anchorHeight + yOffset;

            // Preserve the gravity adjustment.
            if (hgrav == Gravity.RIGHT) {
                p.x -= mPopupWidth - anchorWidth;
                outParams.x -= width - anchorWidth;
            }

            // Determine whether there is more space above or below the anchor.
            anchor.getLocationOnScreen(mScreenLocation);
            onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
                    (mScreenLocation[1] - yoff - displayFrame.top);
            anchor.getLocationOnScreen(screenLocation);
            final int spaceBelow = displayFrame.bottom - screenLocation[1] - anchorHeight - yOffset;
            final int spaceAbove = screenLocation[1] - yOffset - displayFrame.top;
            onTop = spaceBelow < spaceAbove;

            if (!mOverlapAnchor) {
                if (onTop) {
                    p.gravity = Gravity.LEFT | Gravity.BOTTOM;
                    p.y = root.getHeight() - mDrawingLocation[1] + yoff;
                    outParams.gravity = Gravity.LEFT | Gravity.BOTTOM;
                    outParams.y = root.getHeight() - drawingLocation[1] + yOffset;
                } else {
                    p.y = mDrawingLocation[1] + anchorHeight + yoff;
                    outParams.y = drawingLocation[1] + anchorHeight + yOffset;
                }
            }
        } else {
            onTop = false;
        }

        if (mClipToScreen) {
            final int winOffsetX = mScreenLocation[0] - mDrawingLocation[0];
            final int winOffsetY = mScreenLocation[1] - mDrawingLocation[1];
            p.x += winOffsetX;
            p.y += winOffsetY;
            final int displayFrameWidth = displayFrame.right - displayFrame.left;
            final int right = p.x + p.width;
            final int winOffsetX = screenLocation[0] - drawingLocation[0];
            final int winOffsetY = screenLocation[1] - drawingLocation[1];
            outParams.x += winOffsetX;
            outParams.y += winOffsetY;

            final int right = outParams.x + width;
            if (right > displayFrame.right) {
                p.x -= right - displayFrame.right;
                outParams.x -= right - displayFrame.right;
            }

            if (p.x < displayFrame.left) {
                p.x = displayFrame.left;
                p.width = Math.min(p.width, displayFrameWidth);
            if (outParams.x < displayFrame.left) {
                outParams.x = displayFrame.left;

                final int displayFrameWidth = displayFrame.right - displayFrame.left;
                width = Math.min(width, displayFrameWidth);
            }

            if (mOverlapAnchor) {
                final int bottom = p.y + p.height;
                final int bottom = outParams.y + width;
                if (bottom > displayFrame.bottom) {
                    p.y -= bottom - displayFrame.bottom;
                    outParams.y -= bottom - displayFrame.bottom;
                }
            } else {
                if (onTop) {
                    final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
                    final int popupTop = screenLocation[1] + yOffset - height;
                    if (popupTop < 0) {
                        p.y += popupTop;
                        outParams.y += popupTop;
                    }
                } else {
                    p.y = Math.max(p.y, displayFrame.top);
                    outParams.y = Math.max(outParams.y, displayFrame.top);
                }
            }
            p.x -= winOffsetX;
            p.y -= winOffsetY;

            outParams.x -= winOffsetX;
            outParams.y -= winOffsetY;
        }

        p.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;
        outParams.width = width;
        outParams.height = height;
        outParams.gravity |= Gravity.DISPLAY_CLIP_VERTICAL;

        return onTop;
    }
@@ -1665,7 +1676,7 @@ public class PopupWindow {
            anchor.getWindowVisibleDisplayFrame(displayFrame);
        }

        final int[] anchorPos = mDrawingLocation;
        final int[] anchorPos = mTmpDrawingLocation;
        anchor.getLocationOnScreen(anchorPos);

        final int bottomEdge = displayFrame.bottom;
@@ -1754,7 +1765,7 @@ public class PopupWindow {
        }

        // Clears the anchor view.
        unregisterForViewTreeChanges();
        detachFromAnchor();

        if (mOnDismissListener != null) {
            mOnDismissListener.onDismiss();
@@ -2018,43 +2029,40 @@ public class PopupWindow {
        }

        final WeakReference<View> oldAnchor = mAnchor;
        final int gravity = mAnchoredGravity;

        final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
        if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
            registerForViewTreeChanges(anchor, xoff, yoff, mAnchoredGravity);
            attachToAnchor(anchor, xoff, yoff, gravity);
        } else if (needsUpdate) {
            // No need to register again if this is a DropDown, showAsDropDown already did.
            mAnchorXoff = xoff;
            mAnchorYoff = yoff;
        }

        final WindowManager.LayoutParams p =
                (WindowManager.LayoutParams) mDecorView.getLayoutParams();
        final LayoutParams p = (LayoutParams) mDecorView.getLayoutParams();
        final int oldGravity = p.gravity;
        final int oldWidth = p.width;
        final int oldHeight = p.height;
        final int oldX = p.x;
        final int oldY = p.y;

        if (updateDimension) {
            if (width == -1) {
                width = mPopupWidth;
            } else {
                mPopupWidth = width;
                p.width = width;
            }
            if (height == -1) {
                height = mPopupHeight;
            } else {
                mPopupHeight = height;
                p.height  = height;
            }
        }

        final int x = p.x;
        final int y = p.y;
        if (updateLocation) {
            updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, mAnchoredGravity));
        } else {
            updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
                    mAnchoredGravity));
        }
        final boolean aboveAnchor = findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
                width, height, gravity);
        updateAboveAnchor(aboveAnchor);

        update(p.x, p.y, width, height, x != p.x || y != p.y);
        final boolean paramsChanged = oldGravity != p.gravity || oldX != p.x || oldY != p.y
                || oldWidth != p.width || oldHeight != p.height;
        update(p.x, p.y, p.width, p.height, paramsChanged);
    }

    /**
@@ -2067,7 +2075,7 @@ public class PopupWindow {
        public void onDismiss();
    }

    private void unregisterForViewTreeChanges() {
    private void detachFromAnchor() {
        final View anchor = mAnchor != null ? mAnchor.get() : null;
        if (anchor != null) {
            final ViewTreeObserver vto = anchor.getViewTreeObserver();
@@ -2084,8 +2092,8 @@ public class PopupWindow {
        mIsAnchorRootAttached = false;
    }

    private void registerForViewTreeChanges(View anchor, int xoff, int yoff, int gravity) {
        unregisterForViewTreeChanges();
    private void attachToAnchor(View anchor, int xoff, int yoff, int gravity) {
        detachFromAnchor();

        final ViewTreeObserver vto = anchor.getViewTreeObserver();
        if (vto != null) {