summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt3
-rw-r--r--core/java/android/widget/ListPopupWindow.java15
-rw-r--r--core/java/android/widget/PopupMenu.java14
-rw-r--r--core/java/android/widget/PopupWindow.java73
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuPresenter.java2
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java8
6 files changed, 98 insertions, 17 deletions
diff --git a/api/current.txt b/api/current.txt
index c2dfa92..8d7ad8e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31576,6 +31576,7 @@ package android.widget {
method public void setAnimationStyle(int);
method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
method public void setContentWidth(int);
+ method public void setDropDownGravity(int);
method public void setHeight(int);
method public void setHorizontalOffset(int);
method public void setInputMethodMode(int);
@@ -31757,6 +31758,7 @@ package android.widget {
public class PopupMenu {
ctor public PopupMenu(android.content.Context, android.view.View);
+ ctor public PopupMenu(android.content.Context, android.view.View, int);
method public void dismiss();
method public android.view.View.OnTouchListener getDragToOpenListener();
method public android.view.Menu getMenu();
@@ -31820,6 +31822,7 @@ package android.widget {
method public void setWindowLayoutMode(int, int);
method public void showAsDropDown(android.view.View);
method public void showAsDropDown(android.view.View, int, int);
+ method public void showAsDropDown(android.view.View, int, int, int);
method public void showAtLocation(android.view.View, int, int, int);
method public void update();
method public void update(int, int);
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index b7e1fdd..66fe46f 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -28,6 +28,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.IntProperty;
import android.util.Log;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -76,6 +77,8 @@ public class ListPopupWindow {
private int mDropDownVerticalOffset;
private boolean mDropDownVerticalOffsetSet;
+ private int mDropDownGravity = Gravity.NO_GRAVITY;
+
private boolean mDropDownAlwaysVisible = false;
private boolean mForceIgnoreOutsideTouch = false;
int mListItemExpandMaximum = Integer.MAX_VALUE;
@@ -439,6 +442,16 @@ public class ListPopupWindow {
}
/**
+ * Set the gravity of the dropdown list. This is commonly used to
+ * set gravity to START or END for alignment with the anchor.
+ *
+ * @param gravity Gravity value to use
+ */
+ public void setDropDownGravity(int gravity) {
+ mDropDownGravity = gravity;
+ }
+
+ /**
* @return The width of the popup window in pixels.
*/
public int getWidth() {
@@ -610,7 +623,7 @@ public class ListPopupWindow {
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
mPopup.setTouchInterceptor(mTouchInterceptor);
mPopup.showAsDropDown(getAnchorView(),
- mDropDownHorizontalOffset, mDropDownVerticalOffset);
+ mDropDownHorizontalOffset, mDropDownVerticalOffset, mDropDownGravity);
mDropDownList.setSelection(ListView.INVALID_POSITION);
if (!mModal || mDropDownList.isInTouchMode()) {
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 9ac6a59..111dadc 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -22,6 +22,7 @@ import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.SubMenuBuilder;
import android.content.Context;
+import android.view.Gravity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -64,12 +65,25 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
* is room, or above it if there is not.
*/
public PopupMenu(Context context, View anchor) {
+ this(context, anchor, Gravity.NO_GRAVITY);
+ }
+
+ /**
+ * Construct a new PopupMenu.
+ *
+ * @param context Context for the PopupMenu.
+ * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
+ * is room, or above it if there is not.
+ * @param gravity The {@link Gravity} value for aligning the popup with its anchor
+ */
+ public PopupMenu(Context context, View anchor, int gravity) {
// TODO Theme?
mContext = context;
mMenu = new MenuBuilder(context);
mMenu.setCallback(this);
mAnchor = anchor;
mPopup = new MenuPopupHelper(context, mMenu, anchor);
+ mPopup.setGravity(gravity);
mPopup.setCallback(this);
}
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 1460737..5663959 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -72,7 +72,9 @@ public class PopupWindow {
* screen as needed, regardless of whether this covers the input method.
*/
public static final int INPUT_METHOD_NOT_NEEDED = 2;
-
+
+ private static final int DEFAULT_ANCHORED_GRAVITY = Gravity.TOP | Gravity.START;
+
private Context mContext;
private WindowManager mWindowManager;
@@ -135,12 +137,13 @@ public class PopupWindow {
WindowManager.LayoutParams p = (WindowManager.LayoutParams)
mPopupView.getLayoutParams();
- updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff));
+ updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+ mAnchoredGravity));
update(p.x, p.y, -1, -1, true);
}
}
};
- private int mAnchorXoff, mAnchorYoff;
+ private int mAnchorXoff, mAnchorYoff, mAnchoredGravity;
private boolean mPopupViewInitialLayoutDirectionInherited;
@@ -873,15 +876,38 @@ public class PopupWindow {
* location, the popup will be moved correspondingly.</p>
*
* @param anchor the view on which to pin the popup window
+ * @param xoff A horizontal offset from the anchor in pixels
+ * @param yoff A vertical offset from the anchor in pixels
*
* @see #dismiss()
*/
public void showAsDropDown(View anchor, int xoff, int yoff) {
+ showAsDropDown(anchor, xoff, yoff, DEFAULT_ANCHORED_GRAVITY);
+ }
+
+ /**
+ * <p>Display the content view in a popup window anchored to the bottom-left
+ * corner of the anchor view offset by the specified x and y coordinates.
+ * If there is not enough room on screen to show
+ * the popup in its entirety, this method tries to find a parent scroll
+ * view to scroll. If no parent scroll view can be scrolled, the bottom-left
+ * corner of the popup is pinned at the top left corner of the anchor view.</p>
+ * <p>If the view later scrolls to move <code>anchor</code> to a different
+ * location, the popup will be moved correspondingly.</p>
+ *
+ * @param anchor the view on which to pin the popup window
+ * @param xoff A horizontal offset from the anchor in pixels
+ * @param yoff A vertical offset from the anchor in pixels
+ * @param gravity Alignment of the popup relative to the anchor
+ *
+ * @see #dismiss()
+ */
+ public void showAsDropDown(View anchor, int xoff, int yoff, int gravity) {
if (isShowing() || mContentView == null) {
return;
}
- registerForScrollChanged(anchor, xoff, yoff);
+ registerForScrollChanged(anchor, xoff, yoff, gravity);
mIsShowing = true;
mIsDropdown = true;
@@ -889,7 +915,7 @@ public class PopupWindow {
WindowManager.LayoutParams p = createPopupLayout(anchor.getWindowToken());
preparePopup(p);
- updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff));
+ updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));
if (mHeightMode < 0) p.height = mLastHeight = mHeightMode;
if (mWidthMode < 0) p.width = mLastWidth = mWidthMode;
@@ -1105,17 +1131,24 @@ public class PopupWindow {
* @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 xoff, int yoff, int gravity) {
final int anchorHeight = anchor.getHeight();
anchor.getLocationInWindow(mDrawingLocation);
p.x = mDrawingLocation[0] + xoff;
p.y = mDrawingLocation[1] + anchorHeight + yoff;
+
+ 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 - anchor.getWidth();
+ }
boolean onTop = false;
- p.gravity = Gravity.START | Gravity.TOP;
-
+ p.gravity = Gravity.LEFT | Gravity.TOP;
+
anchor.getLocationOnScreen(mScreenLocation);
final Rect displayFrame = new Rect();
anchor.getWindowVisibleDisplayFrame(displayFrame);
@@ -1141,6 +1174,11 @@ public class PopupWindow {
anchor.getLocationInWindow(mDrawingLocation);
p.x = mDrawingLocation[0] + xoff;
p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
+
+ // Preserve the gravity adjustment
+ if (hgrav == Gravity.RIGHT) {
+ p.x -= mPopupWidth - anchor.getWidth();
+ }
// determine whether there is more space above or below the anchor
anchor.getLocationOnScreen(mScreenLocation);
@@ -1148,7 +1186,7 @@ public class PopupWindow {
onTop = (displayFrame.bottom - mScreenLocation[1] - anchor.getHeight() - yoff) <
(mScreenLocation[1] - yoff - displayFrame.top);
if (onTop) {
- p.gravity = Gravity.START | Gravity.BOTTOM;
+ p.gravity = Gravity.LEFT | Gravity.BOTTOM;
p.y = root.getHeight() - mDrawingLocation[1] + yoff;
} else {
p.y = mDrawingLocation[1] + anchor.getHeight() + yoff;
@@ -1436,7 +1474,7 @@ public class PopupWindow {
* @param height the new height, can be -1 to ignore
*/
public void update(View anchor, int width, int height) {
- update(anchor, false, 0, 0, true, width, height);
+ update(anchor, false, 0, 0, true, width, height, mAnchoredGravity);
}
/**
@@ -1455,11 +1493,11 @@ public class PopupWindow {
* @param height the new height, can be -1 to ignore
*/
public void update(View anchor, int xoff, int yoff, int width, int height) {
- update(anchor, true, xoff, yoff, true, width, height);
+ update(anchor, true, xoff, yoff, true, width, height, mAnchoredGravity);
}
private void update(View anchor, boolean updateLocation, int xoff, int yoff,
- boolean updateDimension, int width, int height) {
+ boolean updateDimension, int width, int height, int gravity) {
if (!isShowing() || mContentView == null) {
return;
@@ -1468,11 +1506,12 @@ public class PopupWindow {
WeakReference<View> oldAnchor = mAnchor;
final boolean needsUpdate = updateLocation && (mAnchorXoff != xoff || mAnchorYoff != yoff);
if (oldAnchor == null || oldAnchor.get() != anchor || (needsUpdate && !mIsDropdown)) {
- registerForScrollChanged(anchor, xoff, yoff);
+ registerForScrollChanged(anchor, xoff, yoff, gravity);
} else if (needsUpdate) {
// No need to register again if this is a DropDown, showAsDropDown already did.
mAnchorXoff = xoff;
mAnchorYoff = yoff;
+ mAnchoredGravity = gravity;
}
WindowManager.LayoutParams p = (WindowManager.LayoutParams) mPopupView.getLayoutParams();
@@ -1494,9 +1533,10 @@ public class PopupWindow {
int y = p.y;
if (updateLocation) {
- updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff));
+ updateAboveAnchor(findDropDownPosition(anchor, p, xoff, yoff, gravity));
} else {
- updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff));
+ updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff,
+ mAnchoredGravity));
}
update(p.x, p.y, width, height, x != p.x || y != p.y);
@@ -1525,7 +1565,7 @@ public class PopupWindow {
mAnchor = null;
}
- private void registerForScrollChanged(View anchor, int xoff, int yoff) {
+ private void registerForScrollChanged(View anchor, int xoff, int yoff, int gravity) {
unregisterForScrollChanged();
mAnchor = new WeakReference<View>(anchor);
@@ -1536,6 +1576,7 @@ public class PopupWindow {
mAnchorXoff = xoff;
mAnchorYoff = yoff;
+ mAnchoredGravity = gravity;
}
private class PopupViewContainer extends FrameLayout {
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 4c6ddbf..6471e14 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -25,6 +25,7 @@ import android.transition.Transition;
import android.transition.TransitionManager;
import android.util.SparseBooleanArray;
import android.view.ActionProvider;
+import android.view.Gravity;
import android.view.MenuItem;
import android.view.SoundEffectConstants;
import android.view.View;
@@ -665,6 +666,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
boolean overflowOnly) {
super(context, menu, anchorView, overflowOnly);
+ setGravity(Gravity.END);
setCallback(mPopupPresenterCallback);
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index dbb78c2..05e9a66 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -19,6 +19,7 @@ package com.android.internal.view.menu;
import android.content.Context;
import android.content.res.Resources;
import android.os.Parcelable;
+import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -69,6 +70,8 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
/** Cached content width from {@link #measureContentWidth}. */
private int mContentWidth;
+ private int mDropDownGravity = Gravity.NO_GRAVITY;
+
public MenuPopupHelper(Context context, MenuBuilder menu) {
this(context, menu, null, false);
}
@@ -102,6 +105,10 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
mForceShowIcon = forceShow;
}
+ public void setGravity(int gravity) {
+ mDropDownGravity = gravity;
+ }
+
public void show() {
if (!tryShow()) {
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
@@ -126,6 +133,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
anchor.addOnAttachStateChangeListener(this);
mPopup.setAnchorView(anchor);
+ mPopup.setDropDownGravity(mDropDownGravity);
} else {
return false;
}