Add an API to listen for window attach/detach events on a View.

Fix bug 3312949 - inconsistent state in MenuPopupHelper

Change-Id: Ie802ada3f8de4cf71c92fcc7c6abce9ba85e7b75
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 6c9e7bb..04a059e 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -36,14 +36,15 @@
  * @hide
  */
 public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
-        ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener {
+        ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
+        View.OnAttachStateChangeListener {
     private static final String TAG = "MenuPopupHelper";
 
     private Context mContext;
     private ListPopupWindow mPopup;
     private MenuBuilder mMenu;
     private int mPopupMaxWidth;
-    private WeakReference<View> mAnchorView;
+    private View mAnchorView;
     private boolean mOverflowOnly;
     private ViewTreeObserver mTreeObserver;
 
@@ -66,13 +67,11 @@
         final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
         mPopupMaxWidth = metrics.widthPixels / 2;
 
-        if (anchorView != null) {
-            mAnchorView = new WeakReference<View>(anchorView);
-        }
+        mAnchorView = anchorView;
     }
 
     public void setAnchorView(View anchor) {
-        mAnchorView = new WeakReference<View>(anchor);
+        mAnchorView = anchor;
     }
 
     public void show() {
@@ -92,19 +91,19 @@
         mPopup.setAdapter(adapter);
         mPopup.setModal(true);
 
-        View anchor = mAnchorView != null ? mAnchorView.get() : null;
+        View anchor = mAnchorView;
         if (anchor == null && mMenu instanceof SubMenuBuilder) {
             SubMenuBuilder subMenu = (SubMenuBuilder) mMenu;
             final MenuItemImpl itemImpl = (MenuItemImpl) subMenu.getItem();
             anchor = itemImpl.getItemView(MenuBuilder.TYPE_ACTION_BUTTON, null);
-            mAnchorView = new WeakReference<View>(anchor);
+            mAnchorView = anchor;
         }
 
         if (anchor != null) {
-            if (mTreeObserver == null) {
-                mTreeObserver = anchor.getViewTreeObserver();
-                mTreeObserver.addOnGlobalLayoutListener(this);
-            }
+            final boolean addGlobalListener = mTreeObserver == null;
+            mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
+            if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
+            anchor.addOnAttachStateChangeListener(this);
             mPopup.setAnchorView(anchor);
         } else {
             return false;
@@ -125,10 +124,12 @@
 
     public void onDismiss() {
         mPopup = null;
-        if (mTreeObserver != null && mTreeObserver.isAlive()) {
+        if (mTreeObserver != null) {
+            if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
             mTreeObserver.removeGlobalOnLayoutListener(this);
+            mTreeObserver = null;
         }
-        mTreeObserver = null;
+        mAnchorView.removeOnAttachStateChangeListener(this);
     }
 
     public boolean isShowing() {
@@ -187,13 +188,8 @@
 
     @Override
     public void onGlobalLayout() {
-        if (!isShowing()) {
-            if (mTreeObserver.isAlive()) {
-                mTreeObserver.removeGlobalOnLayoutListener(this);
-            }
-            mTreeObserver = null;
-        } else {
-            final View anchor = mAnchorView != null ? mAnchorView.get() : null;
+        if (isShowing()) {
+            final View anchor = mAnchorView;
             if (anchor == null || !anchor.isShown()) {
                 dismiss();
             } else if (isShowing()) {
@@ -202,4 +198,17 @@
             }
         }
     }
+
+    @Override
+    public void onViewAttachedToWindow(View v) {
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        if (mTreeObserver != null) {
+            if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
+            mTreeObserver.removeGlobalOnLayoutListener(this);
+        }
+        v.removeOnAttachStateChangeListener(this);
+    }
 }