diff options
| -rw-r--r-- | core/java/android/widget/ListPopupWindow.java | 9 | ||||
| -rw-r--r-- | core/java/android/widget/PopupWindow.java | 41 | ||||
| -rw-r--r-- | core/java/com/android/internal/view/menu/CascadingMenuPopup.java | 31 |
3 files changed, 52 insertions, 29 deletions
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 0bde983337f1..3d59f9d429c7 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -75,6 +75,7 @@ public class ListPopupWindow implements ShowableListMenu { private int mDropDownWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; private boolean mDropDownVerticalOffsetSet; private boolean mIsAnimatedFromAnchor = true; + private boolean mOverlapAnchor; private int mDropDownGravity = Gravity.NO_GRAVITY; @@ -668,6 +669,7 @@ public class ListPopupWindow implements ShowableListMenu { mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible); mPopup.setTouchInterceptor(mTouchInterceptor); mPopup.setEpicenterBounds(mEpicenterBounds); + mPopup.setOverlapAnchor(mOverlapAnchor); mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset, mDropDownVerticalOffset, mDropDownGravity); mDropDownList.setSelection(ListView.INVALID_POSITION); @@ -1241,6 +1243,13 @@ public class ListPopupWindow implements ShowableListMenu { return listContent + otherHeights; } + /** + * @hide + */ + public void setOverlapAnchor(boolean overlap) { + mOverlapAnchor = overlap; + } + private class PopupDataSetObserver extends DataSetObserver { @Override public void onChanged() { diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 26b3ae2c42fc..9f10531841e3 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -55,6 +55,7 @@ import android.view.ViewTreeObserver.OnScrollChangedListener; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.view.WindowManager.LayoutParams.SoftInputModeFlags; +import android.view.WindowManagerGlobal; import com.android.internal.R; @@ -137,6 +138,7 @@ public class PopupWindow { private final int[] mTmpDrawingLocation = new int[2]; private final int[] mTmpScreenLocation = new int[2]; + private final int[] mTmpAppLocation = new int[2]; private final Rect mTempRect = new Rect(); private Context mContext; @@ -242,6 +244,9 @@ public class PopupWindow { private final OnScrollChangedListener mOnScrollChangedListener = this::alignToAnchor; + private final View.OnLayoutChangeListener mOnLayoutChangeListener = + (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> alignToAnchor(); + private int mAnchorXoff; private int mAnchorYoff; private int mAnchoredGravity; @@ -1238,7 +1243,8 @@ public class PopupWindow { mIsShowing = true; mIsDropdown = true; - final WindowManager.LayoutParams p = createPopupLayoutParams(anchor.getWindowToken()); + final WindowManager.LayoutParams p = + createPopupLayoutParams(anchor.getApplicationWindowToken()); preparePopup(p); final boolean aboveAnchor = findDropDownPosition(anchor, p, xoff, yoff, @@ -1547,13 +1553,21 @@ public class PopupWindow { } // Initially, align to the bottom-left corner of the anchor plus offsets. + final int[] appScreenLocation = mTmpAppLocation; + final View appRootView = getAppRootView(anchor); + appRootView.getLocationOnScreen(appScreenLocation); + + final int[] screenLocation = mTmpScreenLocation; + anchor.getLocationOnScreen(screenLocation); + final int[] drawingLocation = mTmpDrawingLocation; - anchor.getLocationInWindow(drawingLocation); + drawingLocation[0] = screenLocation[0] - appScreenLocation[0]; + drawingLocation[1] = screenLocation[1] - appScreenLocation[1]; outParams.x = drawingLocation[0] + xOffset; outParams.y = drawingLocation[1] + anchorHeight + yOffset; final Rect displayFrame = new Rect(); - anchor.getWindowVisibleDisplayFrame(displayFrame); + appRootView.getWindowVisibleDisplayFrame(displayFrame); if (width == MATCH_PARENT) { width = displayFrame.right - displayFrame.left; } @@ -1574,9 +1588,6 @@ public class PopupWindow { outParams.x -= width - anchorWidth; } - final int[] screenLocation = mTmpScreenLocation; - anchor.getLocationOnScreen(screenLocation); - // First, attempt to fit the popup vertically without resizing. final boolean fitsVertical = tryFitVertical(outParams, yOffset, height, anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top, @@ -1595,7 +1606,9 @@ public class PopupWindow { scrollY + height + anchorHeight + yOffset); if (allowScroll && anchor.requestRectangleOnScreen(r, true)) { // Reset for the new anchor position. - anchor.getLocationInWindow(drawingLocation); + anchor.getLocationOnScreen(screenLocation); + drawingLocation[0] = screenLocation[0] - appScreenLocation[0]; + drawingLocation[1] = screenLocation[1] - appScreenLocation[1]; outParams.x = drawingLocation[0] + xOffset; outParams.y = drawingLocation[1] + anchorHeight + yOffset; @@ -1793,7 +1806,8 @@ public class PopupWindow { Rect displayFrame = null; final Rect visibleDisplayFrame = new Rect(); - anchor.getWindowVisibleDisplayFrame(visibleDisplayFrame); + final View appView = getAppRootView(anchor); + appView.getWindowVisibleDisplayFrame(visibleDisplayFrame); if (ignoreBottomDecorations) { // In the ignore bottom decorations case we want to // still respect all other decorations so we use the inset visible @@ -2240,6 +2254,7 @@ public class PopupWindow { final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null; if (anchorRoot != null) { anchorRoot.removeOnAttachStateChangeListener(mOnAnchorRootDetachedListener); + anchorRoot.removeOnLayoutChangeListener(mOnLayoutChangeListener); } mAnchor = null; @@ -2258,6 +2273,7 @@ public class PopupWindow { final View anchorRoot = anchor.getRootView(); anchorRoot.addOnAttachStateChangeListener(mOnAnchorRootDetachedListener); + anchorRoot.addOnLayoutChangeListener(mOnLayoutChangeListener); mAnchor = new WeakReference<>(anchor); mAnchorRoot = new WeakReference<>(anchorRoot); @@ -2281,6 +2297,15 @@ public class PopupWindow { } } + private View getAppRootView(View anchor) { + final View appWindowView = WindowManagerGlobal.getInstance().getWindowView( + anchor.getApplicationWindowToken()); + if (appWindowView != null) { + return appWindowView; + } + return anchor.getRootView(); + } + private class PopupDecorView extends FrameLayout { private TransitionListenerAdapter mPendingExitListener; diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java index 1de0af6f31df..29f67b6ca70b 100644 --- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java +++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java @@ -381,6 +381,7 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey if (parentView != null) { // This menu is a cascading submenu anchored to a parent view. + popupWindow.setAnchorView(parentView); popupWindow.setTouchModal(false); popupWindow.setEnterTransition(null); @@ -388,42 +389,30 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey final boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT; mLastPosition = nextMenuPosition; - // A popup anchored to mAnchorView with (0,0) offset would be shown at this position. - final int[] offsetOrigin = new int[2]; - mAnchorView.getLocationOnScreen(offsetOrigin); - offsetOrigin[1] += mAnchorView.getHeight(); - - final int[] parentViewScreenLocation = new int[2]; - parentView.getLocationOnScreen(parentViewScreenLocation); - - // Translate the parent view location into the offset coordinate space. - // If used as horizontal/vertical offsets, these values would position the submenu - // at the exact same position as the parent item. - final int parentOffsetLeft = parentViewScreenLocation[0] - offsetOrigin[0]; - final int parentOffsetTop = parentViewScreenLocation[1] - offsetOrigin[1]; - - // Adjust the horizontal offset to display the submenu to the right or to the left + // Compute the horizontal offset to display the submenu to the right or to the left // of the parent item. // By now, mDropDownGravity is the resolved absolute gravity, so // this should work in both LTR and RTL. final int x; if ((mDropDownGravity & Gravity.RIGHT) == Gravity.RIGHT) { if (showOnRight) { - x = parentOffsetLeft + menuWidth; + x = menuWidth; } else { - x = parentOffsetLeft - parentView.getWidth(); + x = -parentView.getWidth(); } } else { if (showOnRight) { - x = parentOffsetLeft + parentView.getWidth(); + x = parentView.getWidth(); } else { - x = parentOffsetLeft - menuWidth; + x = -menuWidth; } } popupWindow.setHorizontalOffset(x); - // Use the same vertical offset as the parent item. - popupWindow.setVerticalOffset(parentOffsetTop); + // Align with the top edge of the parent view (or the bottom edge when the submenu is + // flipped vertically). + popupWindow.setOverlapAnchor(true); + popupWindow.setVerticalOffset(0); } else { if (mHasXOffset) { popupWindow.setHorizontalOffset(mXOffset); |