Optimize width measurement and cache result in MenuPopupHelper
BUG: 9591217
Change-Id: I0cc2fad39f967e92b2c954f6417430a42dce8e43
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index cacc86b..6d39860 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.res.Resources;
-import android.database.DataSetObserver;
import android.os.Parcelable;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -47,23 +46,28 @@
static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
- private Context mContext;
- private LayoutInflater mInflater;
- private ListPopupWindow mPopup;
- private MenuBuilder mMenu;
- private int mPopupMaxWidth;
+ private final Context mContext;
+ private final LayoutInflater mInflater;
+ private final MenuBuilder mMenu;
+ private final MenuAdapter mAdapter;
+ private final boolean mOverflowOnly;
+ private final int mPopupMaxWidth;
+
private View mAnchorView;
- private boolean mOverflowOnly;
+ private ListPopupWindow mPopup;
private ViewTreeObserver mTreeObserver;
-
- private MenuAdapter mAdapter;
-
private Callback mPresenterCallback;
boolean mForceShowIcon;
private ViewGroup mMeasureParent;
+ /** Whether the cached content width value is valid. */
+ private boolean mHasContentWidth;
+
+ /** Cached content width from {@link #measureContentWidth}. */
+ private int mContentWidth;
+
public MenuPopupHelper(Context context, MenuBuilder menu) {
this(context, menu, null, false);
}
@@ -77,6 +81,7 @@
mContext = context;
mInflater = LayoutInflater.from(context);
mMenu = menu;
+ mAdapter = new MenuAdapter(mMenu);
mOverflowOnly = overflowOnly;
final Resources res = context.getResources();
@@ -106,8 +111,6 @@
mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
mPopup.setOnDismissListener(this);
mPopup.setOnItemClickListener(this);
-
- mAdapter = new MenuAdapter(mMenu);
mPopup.setAdapter(mAdapter);
mPopup.setModal(true);
@@ -122,7 +125,12 @@
return false;
}
- mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth));
+ if (!mHasContentWidth) {
+ mContentWidth = measureContentWidth();
+ mHasContentWidth = true;
+ }
+
+ mPopup.setContentWidth(mContentWidth);
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
mPopup.show();
mPopup.getListView().setOnKeyListener(this);
@@ -164,15 +172,15 @@
return false;
}
- private int measureContentWidth(ListAdapter adapter) {
+ private int measureContentWidth() {
// Menus don't tend to be long, so this is more sane than it looks.
- int width = 0;
+ int maxWidth = 0;
View itemView = null;
int itemType = 0;
- final int widthMeasureSpec =
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
- final int heightMeasureSpec =
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+
+ final ListAdapter adapter = mAdapter;
+ final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final int count = adapter.getCount();
for (int i = 0; i < count; i++) {
final int positionType = adapter.getItemViewType(i);
@@ -180,14 +188,23 @@
itemType = positionType;
itemView = null;
}
+
if (mMeasureParent == null) {
mMeasureParent = new FrameLayout(mContext);
}
+
itemView = adapter.getView(i, itemView, mMeasureParent);
itemView.measure(widthMeasureSpec, heightMeasureSpec);
- width = Math.max(width, itemView.getMeasuredWidth());
+
+ final int itemWidth = itemView.getMeasuredWidth();
+ if (itemWidth >= mPopupMaxWidth) {
+ return mPopupMaxWidth;
+ } else if (itemWidth > maxWidth) {
+ maxWidth = itemWidth;
+ }
}
- return width;
+
+ return maxWidth;
}
@Override
@@ -228,7 +245,11 @@
@Override
public void updateMenuView(boolean cleared) {
- if (mAdapter != null) mAdapter.notifyDataSetChanged();
+ mHasContentWidth = false;
+
+ if (mAdapter != null) {
+ mAdapter.notifyDataSetChanged();
+ }
}
@Override