Ensure only one context menu is shown at a time

Refactors the menu helper classes. Both classes now implement a common
MenuHelper interface, which eliminates the need to keep separate helpers
on PhoneWindow and unifies the DecorView showContextMenuForChild()
implementations.

We now explicitly dismiss any previously shown context menu before showing
a new context menu. Previously we relied on the modal nature of the dialog
context menu to prevent multiple menus from being opened at once, but this
is no longer reliable with popup context menus.

Bug: 25656520
Change-Id: Idab3daa6d6888f803f2e33660fe1dd488e4c28d1
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 27fe03c..a95c401 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -21,8 +21,7 @@
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
-import com.android.internal.view.menu.MenuDialogHelper;
-import com.android.internal.view.menu.MenuPopupHelper;
+import com.android.internal.view.menu.MenuHelper;
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.DecorCaptionView;
@@ -659,30 +658,23 @@
 
     @Override
     public boolean showContextMenuForChild(View originalView) {
-        // Reuse the context menu builder
-        if (mWindow.mContextMenu == null) {
-            mWindow.mContextMenu = new ContextMenuBuilder(getContext());
-            mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
-        } else {
-            mWindow.mContextMenu.clearAll();
-        }
-
-        final MenuDialogHelper helper = mWindow.mContextMenu.show(originalView,
-                originalView.getWindowToken());
-        if (helper != null) {
-            helper.setPresenterCallback(mWindow.mContextMenuCallback);
-        } else if (mWindow.mContextMenuHelper != null) {
-            // No menu to show, but if we have a menu currently showing it just became blank.
-            // Close it.
-            mWindow.mContextMenuHelper.dismiss();
-        }
-        mWindow.mContextMenuHelper = helper;
-        return helper != null;
+        return showContextMenuForChildInternal(originalView, 0, 0, false);
     }
 
     @Override
     public boolean showContextMenuForChild(View originalView, float x, float y) {
-        // Reuse the context menu builder
+        return showContextMenuForChildInternal(originalView, x, y, true);
+    }
+
+    private boolean showContextMenuForChildInternal(View originalView,
+            float x, float y, boolean isPopup) {
+        // Only allow one context menu at a time.
+        if (mWindow.mContextMenuHelper != null) {
+            mWindow.mContextMenuHelper.dismiss();
+            mWindow.mContextMenuHelper = null;
+        }
+
+        // Reuse the context menu builder.
         if (mWindow.mContextMenu == null) {
             mWindow.mContextMenu = new ContextMenuBuilder(getContext());
             mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
@@ -690,16 +682,18 @@
             mWindow.mContextMenu.clearAll();
         }
 
-        final MenuPopupHelper helper = mWindow.mContextMenu.showPopup(
-                getContext(), originalView, x, y);
-        if (helper != null) {
-            helper.setCallback(mWindow.mContextMenuCallback);
-        } else if (mWindow.mContextMenuPopupHelper != null) {
-            // No menu to show, but if we have a menu currently showing it just became blank.
-            // Close it.
-            mWindow.mContextMenuPopupHelper.dismiss();
+        final MenuHelper helper;
+        if (isPopup) {
+            helper = mWindow.mContextMenu.showPopup(getContext(), originalView, x, y);
+        } else {
+            helper = mWindow.mContextMenu.showDialog(originalView, originalView.getWindowToken());
         }
-        mWindow.mContextMenuPopupHelper = helper;
+
+        if (helper != null) {
+            helper.setPresenterCallback(mWindow.mContextMenuCallback);
+        }
+
+        mWindow.mContextMenuHelper = helper;
         return helper != null;
     }