Animate context popup menu around origin point

Also enables the context popup menu enter transition.

Bug: 25801140
Change-Id: Id7fb384e8ac8974189b32a052352bd2f6cbb176e
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 044ee6e..1f1e594 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -23,6 +23,8 @@
 import android.annotation.Nullable;
 import android.annotation.StyleRes;
 import android.content.Context;
+import android.graphics.Rect;
+import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.PopupWindow.OnDismissListener;
@@ -31,6 +33,8 @@
  * Presents a menu as a small, simple popup anchored to another view.
  */
 public class MenuPopupHelper implements MenuHelper {
+    private static final int TOUCH_EPICENTER_SIZE_DP = 48;
+
     private final Context mContext;
 
     // Immutable cached popup menu properties.
@@ -163,6 +167,11 @@
      * Shows the popup menu and makes a best-effort to anchor it to the
      * specified (x,y) coordinate relative to the anchor view.
      * <p>
+     * Additionally, the popup's transition epicenter (see
+     * {@link android.widget.PopupWindow#setEpicenterBounds(Rect)} will be
+     * centered on the specified coordinate, rather than using the bounds of
+     * the anchor view.
+     * <p>
      * If the popup's resolved gravity is {@link Gravity#LEFT}, this will
      * display the popup with its top-left corner at (x,y) relative to the
      * anchor view. If the resolved gravity is {@link Gravity#RIGHT}, the
@@ -222,8 +231,11 @@
         return popup;
     }
 
-    private void showPopup(int xOffset, int yOffset, boolean resolveOffsets, boolean showTitle) {
-        if (resolveOffsets) {
+    private void showPopup(int xOffset, int yOffset, boolean useOffsets, boolean showTitle) {
+        final MenuPopup popup = getPopup();
+        popup.setShowTitle(showTitle);
+
+        if (useOffsets) {
             // If the resolved drop-down gravity is RIGHT, the popup's right
             // edge will be aligned with the anchor view. Adjust by the anchor
             // width such that the top-right corner is at the X offset.
@@ -232,12 +244,21 @@
             if (hgrav == Gravity.RIGHT) {
                 xOffset -= mAnchorView.getWidth();
             }
+
+            popup.setHorizontalOffset(xOffset);
+            popup.setVerticalOffset(yOffset);
+
+            // Set the transition epicenter to be roughly finger (or mouse
+            // cursor) sized and centered around the offset position. This
+            // will give the appearance that the window is emerging from
+            // the touch point.
+            final float density = mContext.getResources().getDisplayMetrics().density;
+            final int halfSize = (int) (TOUCH_EPICENTER_SIZE_DP * density / 2);
+            final Rect epicenter = new Rect(xOffset - halfSize, yOffset - halfSize,
+                    xOffset + halfSize, yOffset + halfSize);
+            popup.setEpicenterBounds(epicenter);
         }
 
-        final MenuPopup popup = getPopup();
-        popup.setHorizontalOffset(xOffset);
-        popup.setVerticalOffset(yOffset);
-        popup.setShowTitle(showTitle);
         popup.show();
     }