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

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

Issue 1068123002: Animate opening and closing of Android page info popup (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review comments Created 5 years, 8 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
index 1c67e4fad0753569b84427c81e5aa809c91324fb..599420e66c5c93ccda9ed5e96fe0f6aaaff0a705 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WebsiteSettingsPopup.java
@@ -4,6 +4,10 @@
package org.chromium.chrome.browser;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -41,9 +45,11 @@ import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.WebContentsObserver;
import org.chromium.ui.base.Clipboard;
import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.interpolators.BakedBezierInterpolator;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -188,6 +194,13 @@ public class WebsiteSettingsPopup implements OnClickListener, OnItemSelectedList
}
}
+ // Delay enter to allow the triggering button to animate before we cover it.
+ private static final int ENTER_START_DELAY = 100;
+ private static final int FADE_DURATION = 200;
+ private static final int FADE_IN_BASE_DELAY = 150;
+ private static final int FADE_IN_DELAY_OFFSET = 20;
+ private static final int CLOSE_CLEANUP_DELAY = 10;
+
private static final int MAX_TABLET_DIALOG_WIDTH_DP = 400;
private final Context mContext;
@@ -213,6 +226,9 @@ public class WebsiteSettingsPopup implements OnClickListener, OnItemSelectedList
// The dialog the container is placed in.
private final Dialog mDialog;
+ // Animation which is currently running, if there is one.
+ private AnimatorSet mCurrentAnimation = null;
+
// The full URL from the URL bar, which is copied to the user's clipboard when they select 'Copy
// URL'.
private String mFullUrl;
@@ -247,6 +263,17 @@ public class WebsiteSettingsPopup implements OnClickListener, OnItemSelectedList
// Find the container and all it's important subviews.
mContainer = (LinearLayout) LayoutInflater.from(mContext).inflate(
R.layout.website_settings, null);
+ mContainer.setVisibility(View.INVISIBLE);
+ mContainer.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
+ public void onLayoutChange(
+ View v, int l, int t, int r, int b, int ol, int ot, int or, int ob) {
+ // Trigger the entrance animations once the main container has been laid out and has
+ // a height.
+ mContainer.removeOnLayoutChangeListener(this);
+ mContainer.setVisibility(View.VISIBLE);
+ createAllAnimations(true).start();
+ }
+ });
mUrlTitle = (ElidedUrlTextView) mContainer.findViewById(R.id.website_settings_url);
mUrlTitle.setProfile(mProfile);
@@ -277,7 +304,36 @@ public class WebsiteSettingsPopup implements OnClickListener, OnItemSelectedList
setVisibilityOfLowerDialogArea(false);
// Create the dialog.
- mDialog = new Dialog(mContext);
+ mDialog = new Dialog(mContext) {
+ private void superDismiss() {
+ super.dismiss();
+ }
+
+ @Override
+ public void dismiss() {
+ if (DeviceFormFactor.isTablet(mContext)) {
+ // Dismiss the dialog without any custom animations on tablet.
+ super.dismiss();
+ } else {
+ Animator animator = createAllAnimations(false);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // onAnimationEnd is called during the final frame of the animation.
+ // Delay the cleanup by a tiny amount to give this frame a chance to be
+ // displayed before we destroy the dialog.
+ mContainer.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ superDismiss();
+ }
+ }, CLOSE_CLEANUP_DELAY);
+ }
+ });
+ animator.start();
+ }
+ }
+ };
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setCanceledOnTouchOutside(true);
@@ -557,6 +613,98 @@ public class WebsiteSettingsPopup implements OnClickListener, OnItemSelectedList
}
/**
+ * Create a list of all the views which we want to individually fade in.
+ */
+ private List<View> collectAnimatableViews() {
+ List<View> animatableViews = new ArrayList<View>();
+ animatableViews.add(mUrlTitle);
+ animatableViews.add(mUrlConnectionMessage);
+ animatableViews.add(mCopyUrlButton);
+ animatableViews.add(mHorizontalSeparator);
+ for (int i = 0; i < mPermissionsList.getChildCount(); i++) {
+ animatableViews.add(mPermissionsList.getChildAt(i));
+ }
+
+ return animatableViews;
+ }
+
+ /**
+ * Create an animator to fade an individual dialog element.
+ */
+ private Animator createInnerFadeAnimator(final View view, int position, boolean isEnter) {
+ ObjectAnimator alphaAnim;
+
+ if (isEnter) {
+ view.setAlpha(0f);
+ alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 1f);
+ alphaAnim.setStartDelay(FADE_IN_BASE_DELAY + FADE_IN_DELAY_OFFSET * position);
+ } else {
+ alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, 0f);
+ }
+
+ alphaAnim.setDuration(FADE_DURATION);
+ return alphaAnim;
+ }
+
+ /**
+ * Create an animator to slide in the entire dialog from the top of the screen.
+ */
+ private Animator createDialogSlideAnimator(boolean isEnter) {
+ final float animHeight = -1f * mContainer.getHeight();
+ ObjectAnimator translateAnim;
+ if (isEnter) {
+ mContainer.setTranslationY(animHeight);
+ translateAnim = ObjectAnimator.ofFloat(mContainer, View.TRANSLATION_Y, 0f);
+ translateAnim.setInterpolator(BakedBezierInterpolator.FADE_IN_CURVE);
+ } else {
+ translateAnim = ObjectAnimator.ofFloat(mContainer, View.TRANSLATION_Y, animHeight);
+ translateAnim.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+ }
+ translateAnim.setDuration(FADE_DURATION);
+ return translateAnim;
+ }
+
+ /**
+ * Create animations for showing/hiding the popup.
+ *
+ * Tablets use the default Dialog fade-in instead of sliding in manually.
+ */
+ private Animator createAllAnimations(boolean isEnter) {
+ AnimatorSet animation = new AnimatorSet();
+ AnimatorSet.Builder builder = null;
+ Animator startAnim;
+
+ if (DeviceFormFactor.isTablet(mContext)) {
+ // The start time of the entire AnimatorSet is the start time of the first animation
+ // added to the Builder. We use a blank AnimatorSet on tablet as an easy way to
+ // co-ordinate this start time.
+ startAnim = new AnimatorSet();
+ } else {
+ startAnim = createDialogSlideAnimator(isEnter);
+ }
+
+ if (isEnter) startAnim.setStartDelay(ENTER_START_DELAY);
+ builder = animation.play(startAnim);
+
+ List<View> animatableViews = collectAnimatableViews();
+ for (int i = 0; i < animatableViews.size(); i++) {
+ View view = animatableViews.get(i);
+ Animator anim = createInnerFadeAnimator(view, i, isEnter);
+ builder.with(anim);
+ }
+
+ animation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCurrentAnimation = null;
+ }
+ });
+ if (mCurrentAnimation != null) mCurrentAnimation.cancel();
+ mCurrentAnimation = animation;
+ return animation;
+ }
+
+ /**
* Shows a WebsiteSettings dialog for the provided WebContents. The popup adds itself to the
* view hierarchy which owns the reference while it's visible.
*
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698