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

Commit afaa932e authored by Vladislav Kaznacheev's avatar Vladislav Kaznacheev
Browse files

Do not move PopupWindow when its anchor is detached

The current PopupWindow implementation might call
the anchor view's getLocationInWindow even if the anchor
is currently detached from the window (and the location is
a meaningless (0,0)). This results in the popup jumping to
the top of the screen.

This patch is adding tracking of the anchor's attachment state.
The position is never updated while the anchor is detached.
When the anchor is re-attached, the popup position is updated.

Bug: 34853580
Test: manual (see bug)
Change-Id: Icca1b9b558a70ee3edbe6236e076d2d08a1f8f11
parent d0e10222
Loading
Loading
Loading
Loading
+30 −14
Original line number Diff line number Diff line
@@ -208,6 +208,21 @@ public class PopupWindow {
        com.android.internal.R.attr.state_above_anchor
    };

    private final OnAttachStateChangeListener mOnAnchorDetachedListener =
            new OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    // Anchor might have been reattached in a different position.
                    alignToAnchor();
                }

                @Override
                public void onViewDetachedFromWindow(View v) {
                    // Leave the popup in its current position.
                    // The anchor might become attached again.
                }
            };

    private final OnAttachStateChangeListener mOnAnchorRootDetachedListener =
            new OnAttachStateChangeListener() {
                @Override
@@ -223,20 +238,7 @@ public class PopupWindow {
    private WeakReference<View> mAnchorRoot;
    private boolean mIsAnchorRootAttached;

    private final OnScrollChangedListener mOnScrollChangedListener = new OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            final View anchor = mAnchor != null ? mAnchor.get() : null;
            if (anchor != null && mDecorView != null) {
                final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
                        mDecorView.getLayoutParams();

                updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
                        p.width, p.height, mAnchoredGravity, false));
                update(p.x, p.y, -1, -1, true);
            }
        }
    };
    private final OnScrollChangedListener mOnScrollChangedListener = this::alignToAnchor;

    private int mAnchorXoff;
    private int mAnchorYoff;
@@ -2214,6 +2216,7 @@ public class PopupWindow {
        if (anchor != null) {
            final ViewTreeObserver vto = anchor.getViewTreeObserver();
            vto.removeOnScrollChangedListener(mOnScrollChangedListener);
            anchor.removeOnAttachStateChangeListener(mOnAnchorDetachedListener);
        }

        final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null;
@@ -2233,6 +2236,7 @@ public class PopupWindow {
        if (vto != null) {
            vto.addOnScrollChangedListener(mOnScrollChangedListener);
        }
        anchor.addOnAttachStateChangeListener(mOnAnchorDetachedListener);

        final View anchorRoot = anchor.getRootView();
        anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener);
@@ -2247,6 +2251,18 @@ public class PopupWindow {
        mAnchoredGravity = gravity;
    }

    private void alignToAnchor() {
        final View anchor = mAnchor != null ? mAnchor.get() : null;
        if (anchor != null && anchor.isAttachedToWindow() && mDecorView != null) {
            final WindowManager.LayoutParams p = (WindowManager.LayoutParams)
                    mDecorView.getLayoutParams();

            updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
                    p.width, p.height, mAnchoredGravity, false));
            update(p.x, p.y, -1, -1, true);
        }
    }

    private class PopupDecorView extends FrameLayout {
        private TransitionListenerAdapter mPendingExitListener;