Commit afb450fc authored by Amirhossein Simjour's avatar Amirhossein Simjour Committed by Commit Bot

Using AnchoredPopupWindow for DropdownPopupWindow

DropdownPopupWindow uses AnchoredPopupWindow instead of using
ListPopupWindow. This should potentially fix the positioning problem
of DropdownPopupWindow.

BUG=809758

Change-Id: I246aca46f28b0c71cccadee3d7d12208f6f58268
Reviewed-on: https://chromium-review.googlesource.com/923426
Commit-Queue: Amirhossein Simjour <asimjour@chromium.org>
Reviewed-by: default avatarTheresa <twellington@chromium.org>
Cr-Commit-Position: refs/heads/master@{#542129}
parent 83931b97
...@@ -223,7 +223,8 @@ public class ListMenuButton ...@@ -223,7 +223,8 @@ public class ListMenuButton
mPopupMenu = new AnchoredPopupWindow(getContext(), this, mPopupMenu = new AnchoredPopupWindow(getContext(), this,
ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.menu_bg), contentView, ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.menu_bg), contentView,
rectProvider); rectProvider);
mPopupMenu.setOverlapAnchor(true); mPopupMenu.setVerticalOverlapAnchor(true);
mPopupMenu.setHorizontalOverlapAnchor(true);
mPopupMenu.setMaxWidth(mMenuWidth); mPopupMenu.setMaxWidth(mMenuWidth);
mPopupMenu.setFocusable(true); mPopupMenu.setFocusable(true);
mPopupMenu.setLayoutObserver(this); mPopupMenu.setLayoutObserver(this);
......
...@@ -7,10 +7,6 @@ ...@@ -7,10 +7,6 @@
--> -->
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<style name="DropdownPopupWindow" parent="@android:style/Widget.ListPopupWindow">
<item name="android:popupBackground">@drawable/dropdown_popup_background</item>
</style>
<!-- Buttons --> <!-- Buttons -->
<style name="ButtonCompatOverlay"> <style name="ButtonCompatOverlay">
<item name="android:buttonStyle">@style/ButtonCompat</item> <item name="android:buttonStyle">@style/ButtonCompat</item>
......
...@@ -6,25 +6,23 @@ package org.chromium.ui; ...@@ -6,25 +6,23 @@ package org.chromium.ui;
import android.content.Context; import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.util.Log; import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import android.view.View.OnLayoutChangeListener; import android.view.View.OnLayoutChangeListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ListAdapter; import android.widget.ListAdapter;
import android.widget.ListPopupWindow;
import android.widget.ListView; import android.widget.ListView;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.ui.widget.AnchoredPopupWindow;
import java.lang.reflect.Method; import org.chromium.ui.widget.ViewRectProvider;
/** /**
* The dropdown list popup window. * The dropdown list popup window.
*/ */
public class DropdownPopupWindow { public class DropdownPopupWindow implements AnchoredPopupWindow.LayoutObserver {
private final Context mContext; private final Context mContext;
private final View mAnchorView; private final View mAnchorView;
private boolean mRtl; private boolean mRtl;
...@@ -32,8 +30,10 @@ public class DropdownPopupWindow { ...@@ -32,8 +30,10 @@ public class DropdownPopupWindow {
private OnLayoutChangeListener mLayoutChangeListener; private OnLayoutChangeListener mLayoutChangeListener;
private PopupWindow.OnDismissListener mOnDismissListener; private PopupWindow.OnDismissListener mOnDismissListener;
private CharSequence mDescription; private CharSequence mDescription;
private ListPopupWindow mListPopupWindow; private AnchoredPopupWindow mAnchoredPopupWindow;
ListAdapter mAdapter; ListAdapter mAdapter;
private ListView mListView;
private Drawable mBackground;
/** /**
* Creates an DropdownPopupWindow with specified parameters. * Creates an DropdownPopupWindow with specified parameters.
...@@ -41,7 +41,6 @@ public class DropdownPopupWindow { ...@@ -41,7 +41,6 @@ public class DropdownPopupWindow {
* @param anchorView Popup view to be anchored. * @param anchorView Popup view to be anchored.
*/ */
public DropdownPopupWindow(Context context, View anchorView) { public DropdownPopupWindow(Context context, View anchorView) {
mListPopupWindow = new ListPopupWindow(context, null, 0, R.style.DropdownPopupWindow);
mContext = context; mContext = context;
mAnchorView = anchorView; mAnchorView = anchorView;
...@@ -57,7 +56,7 @@ public class DropdownPopupWindow { ...@@ -57,7 +56,7 @@ public class DropdownPopupWindow {
}; };
mAnchorView.addOnLayoutChangeListener(mLayoutChangeListener); mAnchorView.addOnLayoutChangeListener(mLayoutChangeListener);
mListPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { PopupWindow.OnDismissListener onDismissLitener = new PopupWindow.OnDismissListener() {
@Override @Override
public void onDismiss() { public void onDismiss() {
if (mOnDismissListener != null) { if (mOnDismissListener != null) {
...@@ -66,12 +65,16 @@ public class DropdownPopupWindow { ...@@ -66,12 +65,16 @@ public class DropdownPopupWindow {
mAnchorView.removeOnLayoutChangeListener(mLayoutChangeListener); mAnchorView.removeOnLayoutChangeListener(mLayoutChangeListener);
mAnchorView.setTag(null); mAnchorView.setTag(null);
} }
}); };
mListView = new ListView(context);
mListPopupWindow.setAnchorView(mAnchorView); ViewRectProvider rectProvider = new ViewRectProvider(mAnchorView);
Rect originalPadding = new Rect(); rectProvider.setIncludePadding(true);
mListPopupWindow.getBackground().getPadding(originalPadding); mBackground = ApiCompatibilityUtils.getDrawable(
mListPopupWindow.setVerticalOffset(-originalPadding.top); context.getResources(), R.drawable.dropdown_popup_background);
mAnchoredPopupWindow =
new AnchoredPopupWindow(context, mAnchorView, mBackground, mListView, rectProvider);
mAnchoredPopupWindow.addOnDismissListener(onDismissLitener);
mAnchoredPopupWindow.setLayoutObserver(this);
} }
/** /**
...@@ -82,9 +85,20 @@ public class DropdownPopupWindow { ...@@ -82,9 +85,20 @@ public class DropdownPopupWindow {
*/ */
public void setAdapter(ListAdapter adapter) { public void setAdapter(ListAdapter adapter) {
mAdapter = adapter; mAdapter = adapter;
mListPopupWindow.setAdapter(adapter); mListView.setAdapter(adapter);
mAnchoredPopupWindow.onRectChanged();
} }
@Override
public void onPreLayoutChange(
boolean positionBelow, int x, int y, int width, int height, Rect anchorRect) {
mBackground.setBounds(anchorRect);
mAnchoredPopupWindow.setBackgroundDrawable(positionBelow
? ApiCompatibilityUtils.getDrawable(mContext.getResources(),
R.drawable.dropdown_popup_background_down)
: ApiCompatibilityUtils.getDrawable(mContext.getResources(),
R.drawable.dropdown_popup_background_up));
}
public void setInitialSelection(int initialSelection) { public void setInitialSelection(int initialSelection) {
mInitialSelection = initialSelection; mInitialSelection = initialSelection;
...@@ -94,37 +108,23 @@ public class DropdownPopupWindow { ...@@ -94,37 +108,23 @@ public class DropdownPopupWindow {
* Shows the popup. The adapter should be set before calling this method. * Shows the popup. The adapter should be set before calling this method.
*/ */
public void show() { public void show() {
// An ugly hack to keep the popup from expanding on top of the keyboard.
mListPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED);
assert mAdapter != null : "Set the adapter before showing the popup."; assert mAdapter != null : "Set the adapter before showing the popup.";
final int contentWidth = UiUtils.computeMaxWidthOfListAdapterItems(mAdapter); boolean wasShowing = mAnchoredPopupWindow.isShowing();
final float anchorWidth = mAnchorView.getLayoutParams().width; mAnchoredPopupWindow.setVerticalOverlapAnchor(false);
assert anchorWidth > 0; mAnchoredPopupWindow.setHorizontalOverlapAnchor(true);
Rect padding = new Rect(); mAnchoredPopupWindow.setMaxWidth(measureContentWidth()
mListPopupWindow.getBackground().getPadding(padding); + mContext.getResources().getDimensionPixelSize(
if (contentWidth + padding.left + padding.right > anchorWidth) { R.dimen.dropdown_item_label_margin));
mListPopupWindow.setContentWidth(contentWidth); mAnchoredPopupWindow.show();
final Rect displayFrame = new Rect(); mListView.setDividerHeight(0);
mAnchorView.getWindowVisibleDisplayFrame(displayFrame); ApiCompatibilityUtils.setLayoutDirection(
if (mListPopupWindow.getWidth() > displayFrame.width()) { mListView, mRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
mListPopupWindow.setWidth(displayFrame.width());
}
} else {
mListPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
}
boolean wasShowing = mListPopupWindow.isShowing();
mListPopupWindow.show();
mListPopupWindow.getListView().setDividerHeight(0);
ApiCompatibilityUtils.setLayoutDirection(mListPopupWindow.getListView(),
mRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
if (!wasShowing) { if (!wasShowing) {
mListPopupWindow.getListView().setContentDescription(mDescription); mListView.setContentDescription(mDescription);
mListPopupWindow.getListView().sendAccessibilityEvent( mListView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
} }
if (mInitialSelection >= 0) { if (mInitialSelection >= 0) {
mListPopupWindow.getListView().setSelection(mInitialSelection); mListView.setSelection(mInitialSelection);
mInitialSelection = -1; mInitialSelection = -1;
} }
} }
...@@ -151,19 +151,7 @@ public class DropdownPopupWindow { ...@@ -151,19 +151,7 @@ public class DropdownPopupWindow {
* will not hide the popup. * will not hide the popup.
*/ */
public void disableHideOnOutsideTap() { public void disableHideOnOutsideTap() {
// HACK: The ListPopupWindow's mPopup automatically dismisses on an outside tap. There's mAnchoredPopupWindow.setDismissOnTouchInteraction(false);
// no way to override it or prevent it, except reaching into ListPopupWindow's hidden
// API. This allows the C++ controller to completely control showing/hiding the popup.
// See http://crbug.com/400601
try {
Method setForceIgnoreOutsideTouch = ListPopupWindow.class.getMethod(
"setForceIgnoreOutsideTouch", new Class[] { boolean.class });
setForceIgnoreOutsideTouch.invoke(mListPopupWindow, new Object[] {true});
} catch (Exception e) {
Log.e("AutofillPopup",
"ListPopupWindow.setForceIgnoreOutsideTouch not found",
e);
}
} }
/** /**
...@@ -181,7 +169,7 @@ public class DropdownPopupWindow { ...@@ -181,7 +169,7 @@ public class DropdownPopupWindow {
* @param clickListener Listener to register * @param clickListener Listener to register
*/ */
public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) { public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
mListPopupWindow.setOnItemClickListener(clickListener); mListView.setOnItemClickListener(clickListener);
} }
/** /**
...@@ -189,28 +177,28 @@ public class DropdownPopupWindow { ...@@ -189,28 +177,28 @@ public class DropdownPopupWindow {
* Post a {@link #show()} call to the UI thread. * Post a {@link #show()} call to the UI thread.
*/ */
public void postShow() { public void postShow() {
mListPopupWindow.postShow(); mAnchoredPopupWindow.show();
} }
/** /**
* Disposes of the popup window. * Disposes of the popup window.
*/ */
public void dismiss() { public void dismiss() {
mListPopupWindow.dismiss(); mAnchoredPopupWindow.dismiss();
} }
/** /**
* @return The {@link ListView} displayed within the popup window. * @return The {@link ListView} displayed within the popup window.
*/ */
public ListView getListView() { public ListView getListView() {
return mListPopupWindow.getListView(); return mListView;
} }
/** /**
* @return Whether the popup is currently showing. * @return Whether the popup is currently showing.
*/ */
public boolean isShowing() { public boolean isShowing() {
return mListPopupWindow.isShowing(); return mAnchoredPopupWindow.isShowing();
} }
/** /**
......
...@@ -149,7 +149,8 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ ...@@ -149,7 +149,8 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ
private boolean mPositionBelow; private boolean mPositionBelow;
private boolean mPositionToLeft; private boolean mPositionToLeft;
private boolean mOverlapAnchor; private boolean mVerticalOverlapAnchor;
private boolean mHorizontalOverlapAnchor;
/** /**
* Constructs an {@link AnchoredPopupWindow} instance. * Constructs an {@link AnchoredPopupWindow} instance.
...@@ -295,12 +296,29 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ ...@@ -295,12 +296,29 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ
} }
/** /**
* Sets whether the popup should overlap the anchor {@link Rect}. Defaults to false. This * Sets whether the popup should horizontally overlap the anchor {@link Rect}.
* should be called before the popup is shown. * Defaults to false. This should be called before the popup is shown.
* @param overlap Whether the popup should overlap the anchor. * @param overlap Whether the popup should overlap the anchor.
*/ */
public void setOverlapAnchor(boolean overlap) { public void setHorizontalOverlapAnchor(boolean overlap) {
mOverlapAnchor = overlap; mHorizontalOverlapAnchor = overlap;
}
/**
* Sets whether the popup should vertically overlap the anchor {@link Rect}.
* Defaults to false. This should be called before the popup is shown.
* @param overlap Whether the popup should overlap the anchor.
*/
public void setVerticalOverlapAnchor(boolean overlap) {
mVerticalOverlapAnchor = overlap;
}
/**
* Changes the background of the popup.
* @param background The {@link Drawable} that is set to be background.
*/
public void setBackgroundDrawable(Drawable background) {
mPopupWindow.setBackgroundDrawable(background);
} }
// RectProvider.Observer implementation. // RectProvider.Observer implementation.
...@@ -353,10 +371,11 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ ...@@ -353,10 +371,11 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ
// TODO(dtrainor): This follows the previous logic. But we should look into if we want to // TODO(dtrainor): This follows the previous logic. But we should look into if we want to
// use the root view dimensions instead of the window dimensions here so the popup can't // use the root view dimensions instead of the window dimensions here so the popup can't
// bleed onto the decorations. // bleed onto the decorations.
int spaceAboveAnchor = (mOverlapAnchor ? anchorRect.bottom : anchorRect.top) int spaceAboveAnchor = (mVerticalOverlapAnchor ? anchorRect.bottom : anchorRect.top)
- mCachedWindowRect.top - paddingY - mMarginPx; - mCachedWindowRect.top - paddingY - mMarginPx;
int spaceBelowAnchor = mCachedWindowRect.bottom int spaceBelowAnchor = mCachedWindowRect.bottom
- (mOverlapAnchor ? anchorRect.top : anchorRect.bottom) - paddingY - mMarginPx; - (mVerticalOverlapAnchor ? anchorRect.top : anchorRect.bottom) - paddingY
- mMarginPx;
// Bias based on the center of the popup and where it is on the screen. // Bias based on the center of the popup and where it is on the screen.
boolean idealFitsBelow = idealContentHeight <= spaceBelowAnchor; boolean idealFitsBelow = idealContentHeight <= spaceBelowAnchor;
...@@ -382,9 +401,9 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ ...@@ -382,9 +401,9 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ
if (mPreferredHorizontalOrientation == HORIZONTAL_ORIENTATION_MAX_AVAILABLE_SPACE) { if (mPreferredHorizontalOrientation == HORIZONTAL_ORIENTATION_MAX_AVAILABLE_SPACE) {
int spaceLeftOfAnchor = int spaceLeftOfAnchor =
getSpaceLeftOfAnchor(anchorRect, mCachedWindowRect, mOverlapAnchor); getSpaceLeftOfAnchor(anchorRect, mCachedWindowRect, mHorizontalOverlapAnchor);
int spaceRightOfAnchor = int spaceRightOfAnchor =
getSpaceRightOfAnchor(anchorRect, mCachedWindowRect, mOverlapAnchor); getSpaceRightOfAnchor(anchorRect, mCachedWindowRect, mHorizontalOverlapAnchor);
mPositionToLeft = shouldPositionLeftOfAnchor(spaceLeftOfAnchor, spaceRightOfAnchor, mPositionToLeft = shouldPositionLeftOfAnchor(spaceLeftOfAnchor, spaceRightOfAnchor,
idealContentWidth + paddingY + mMarginPx, currentPositionToLeft, idealContentWidth + paddingY + mMarginPx, currentPositionToLeft,
preferCurrentOrientation); preferCurrentOrientation);
...@@ -401,9 +420,9 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ ...@@ -401,9 +420,9 @@ public class AnchoredPopupWindow implements OnTouchListener, RectProvider.Observ
mHeight = contentView.getMeasuredHeight() + paddingY; mHeight = contentView.getMeasuredHeight() + paddingY;
// Determine the position of the text popup. // Determine the position of the text popup.
mX = getPopupX(anchorRect, mCachedWindowRect, mWidth, mMarginPx, mOverlapAnchor, mX = getPopupX(anchorRect, mCachedWindowRect, mWidth, mMarginPx, mHorizontalOverlapAnchor,
mPreferredHorizontalOrientation, mPositionToLeft); mPreferredHorizontalOrientation, mPositionToLeft);
mY = getPopupY(anchorRect, mHeight, mOverlapAnchor, mPositionBelow); mY = getPopupY(anchorRect, mHeight, mVerticalOverlapAnchor, mPositionBelow);
if (mLayoutObserver != null) { if (mLayoutObserver != null) {
mLayoutObserver.onPreLayoutChange(mPositionBelow, mX, mY, mWidth, mHeight, anchorRect); mLayoutObserver.onPreLayoutChange(mPositionBelow, mX, mY, mWidth, mHeight, anchorRect);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment