Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(82)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java

Issue 2868403003: added scale animation for context menu (Closed)
Patch Set: comments Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..37e8a4aa8b2b56afaefeb36ae4796ef5dfb0428a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ContextMenuDialog.java
@@ -0,0 +1,177 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.widget;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.support.v4.view.animation.LinearOutSlowInInterpolator;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnLayoutChangeListener;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.ScaleAnimation;
+
+import org.chromium.content.browser.RenderCoordinates;
+
+/**
+ * ContextMenuDialog is a subclass of AlwaysDismissedDialog that ensures that the proper scale
+ * animation is played upon calling dismiss().
+ */
+public class ContextMenuDialog extends AlwaysDismissedDialog {
+ private static final int ENTER_ANIMATION_DURATION = 250;
+ // Exit animation duration should be set to 60% of the enter animation duration.
+ private static final int EXIT_ANIMATION_DURATION = 150;
+
+ private View mContentView;
+ private float mContextMenuSourceX;
+ private float mContextMenuSourceY;
+ private int mContextMenuFirstLocationY;
+
+ public ContextMenuDialog(Activity ownerActivity, int theme) {
+ super(ownerActivity, theme);
+ }
+
+ /**
+ * @param contentView The content view to run the animation on.
+ * @param touchPointX The x-coordinate of the touch that triggered the context menu in pixels.
+ * @param touchPointY The y-coordinate of the touch that triggered the context menu in pixels.
+ * @param activity Activity to determine the number of pixels to the left and above of the
+ * window.
+ * @param renderCoordinates Render coordinates to determine the y offset taken by non content
+ * window items.
+ */
+ public void setupEnterAnimationAndShow(final View contentView, final float touchPointX,
Theresa 2017/05/24 22:50:50 How about an init() methods that takes all of thes
Daniel Park 2017/05/25 17:12:36 Done.
+ final float touchPointY, final Activity activity,
+ final RenderCoordinates renderCoordinates) {
+ mContentView = contentView;
+ mContentView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ ViewGroup group = (ViewGroup) v;
+ for (int i = 0; i < group.getChildCount(); i++) {
+ if (group.getChildAt(i).getHeight() == 0
+ && group.getChildAt(i).getVisibility() == View.VISIBLE) {
+ // Return early because not all the views have been measured, so animation
+ // pivots will be off.
+ return;
+ }
+ }
+ mContentView.setVisibility(View.VISIBLE);
+ startEnterAnimation(touchPointX, touchPointY, activity, renderCoordinates);
+ mContentView.removeOnLayoutChangeListener(this);
+ }
+ });
+ super.show();
+ }
+
+ /**
+ * @param touchPointX The x-coordinate of the touch that triggered the context menu in pixels.
+ * @param touchPointY The y-coordinate of the touch that triggered the context menu in pixels.
+ * @param activity Activity to determine the number of pixels to the left and above of the
+ * window.
+ * @param renderCoordinates Render coordinates to determine the y offset taken by non content
+ * window items.
+ */
+ private void startEnterAnimation(float touchPointX, float touchPointY, Activity activity,
+ RenderCoordinates renderCoordinates) {
+ int[] currentLocationOnScreen = new int[2];
+ mContentView.getLocationOnScreen(currentLocationOnScreen);
+
+ mContextMenuFirstLocationY = currentLocationOnScreen[1];
+ Animation animation = getStartAnimation(
+ touchPointX, touchPointY, currentLocationOnScreen, activity, renderCoordinates);
+ mContentView.startAnimation(animation);
+ }
+
+ /**
+ * @param touchPointX The x-coordinate of the touch that triggered the context menu in pixels.
+ * @param touchPointY The y-coordinate of the touch that triggered the context menu in pixels.
+ * @param currentLocationOnScreen A 2-element array that stores the x,y coordinates of the view
+ * in its 0th and 1st indices respectively.
+ * @param activity Activity to determine the number of pixels to the left and above of the
+ * window.
+ * @param renderCoordinates Render coordinates to determine the y offset taken by non content
+ * window items.
+ */
+ private Animation getStartAnimation(float touchPointX, float touchPointY,
Theresa 2017/05/24 22:50:50 I would combine this with startEnterAnimation(). T
Daniel Park 2017/05/25 17:12:37 Done.
+ int[] currentLocationOnScreen, Activity activity, RenderCoordinates renderCoordinates) {
+ Rect rectangle = new Rect();
+ Window window = activity.getWindow();
+ window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
+
+ float xOffset = rectangle.left;
+ float yOffset = rectangle.top + renderCoordinates.getContentOffsetYPix();
+
+ mContextMenuSourceX = touchPointX - currentLocationOnScreen[0] + xOffset;
+ mContextMenuSourceY = touchPointY - currentLocationOnScreen[1] + yOffset;
+
+ return getScaleAnimation(true, mContextMenuSourceX, mContextMenuSourceY);
+ }
+
+ @Override
+ public void dismiss() {
+ int[] contextMenuFinalLocation = new int[2];
+ mContentView.getLocationOnScreen(contextMenuFinalLocation);
+ // Recalculate mContextMenuDestinationY because the context menu's final location may not be
+ // the same as its first location if it changed in height.
+ float contextMenuDestinationY =
+ mContextMenuSourceY + (mContextMenuFirstLocationY - contextMenuFinalLocation[1]);
+
+ Animation exitAnimation =
+ getScaleAnimation(false, mContextMenuSourceX, contextMenuDestinationY);
+ exitAnimation.setAnimationListener(new AnimationListener() {
+
+ @Override
+ public void onAnimationStart(Animation animation) {}
+
+ @Override
+ public void onAnimationRepeat(Animation animation) {}
+
+ @Override
+ public void onAnimationEnd(Animation animation) {
+ ContextMenuDialog.super.dismiss();
+ }
+ });
+ mContentView.startAnimation(exitAnimation);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ this.dismiss();
Theresa 2017/05/24 22:50:50 Just to confirm onTouchEvent() doesn't get called
Daniel Park 2017/05/25 17:12:37 from testing, it does get called when an item is c
Daniel Park 2017/05/25 17:12:37 Done.
+ }
+ return true;
+ }
+
+ /**
+ * @param isEnterAnimation Whether or not the animation will be for when the context menu enters
+ * or not.
Theresa 2017/05/24 22:50:50 nit: "Whether animation is for showing the context
Daniel Park 2017/05/25 17:12:37 Done.
+ * @param pivotX The X coordinate of the point about which the object is being scaled, specified
+ * as an absolute number where 0 is the left edge.
+ * @param pivotY The Y coordinate of the point about which the object is being scaled, specified
+ * as an absolute number where 0 is the top edge.
+ * @return Returns the scale animation for the context menu.
+ */
+ public Animation getScaleAnimation(boolean isEnterAnimation, float pivotX, float pivotY) {
+ float fromX = isEnterAnimation ? 0f : 1f;
+ float toX = isEnterAnimation ? 1f : 0f;
+ float fromY = fromX;
+ float toY = toX;
+
+ ScaleAnimation animation = new ScaleAnimation(
+ fromX, toX, fromY, toY, Animation.ABSOLUTE, pivotX, Animation.ABSOLUTE, pivotY);
+
+ long duration = isEnterAnimation ? ENTER_ANIMATION_DURATION : EXIT_ANIMATION_DURATION;
+
+ animation.setDuration(duration);
+ animation.setInterpolator(new LinearOutSlowInInterpolator());
+ return animation;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698