| 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.
|
| *
|
|
|