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