From 4a463aaab826c926db794bd78433c550c8b32e68 Mon Sep 17 00:00:00 2001 From: tomnatan Date: Fri, 4 Feb 2022 12:54:20 +0000 Subject: [PATCH] [7/n] Letterbox Education: add enter/exit animation to the dialog. Bug: 207010227 Test: N/A Change-Id: Ie5f88b97c16a7bd043c6c63a8693415563b56a54 --- .../letterbox_education_dialog_layout.xml | 5 +- .../LetterboxEduAnimationController.java | 197 ++++++++++++++++++ .../LetterboxEduDialogLayout.java | 21 +- .../LetterboxEduWindowManager.java | 26 ++- 4 files changed, 242 insertions(+), 7 deletions(-) create mode 100644 libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduAnimationController.java diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml index fc6ea9a57e10d..5beaa8798247d 100644 --- a/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml +++ b/libs/WindowManager/Shell/res/layout/letterbox_education_dialog_layout.xml @@ -22,6 +22,8 @@ + + android:padding="24dp" + android:alpha="0"> dialogContainer.setAlpha(1), + /* endCallback= */ () -> { + mDialogAnimation = null; + endCallback.run(); + })); + + mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(), + /* endAlpha= */ LetterboxEduDialogLayout.BACKGROUND_DIM_ALPHA, + mDialogAnimation.getDuration()); + mBackgroundDimAnimator.addListener(getDimAnimatorListener()); + + dialogContainer.startAnimation(mDialogAnimation); + mBackgroundDimAnimator.start(); + } + + /** + * Starts both the background dim fade-out animation and the dialog exit animation. + */ + void startExitAnimation(@Nullable LetterboxEduDialogLayout layout, Runnable endCallback) { + // Cancel any previous animation if it's still running. + cancelAnimation(); + + if (layout == null) { + endCallback.run(); + return; + } + + final View dialogContainer = layout.getDialogContainer(); + mDialogAnimation = loadAnimation(WindowAnimation_windowExitAnimation); + if (mDialogAnimation == null) { + endCallback.run(); + return; + } + mDialogAnimation.setAnimationListener(getAnimationListener( + /* startCallback= */ () -> {}, + /* endCallback= */ () -> { + dialogContainer.setAlpha(0); + mDialogAnimation = null; + endCallback.run(); + })); + + mBackgroundDimAnimator = getAlphaAnimator(layout.getBackgroundDim(), /* endAlpha= */ 0, + mDialogAnimation.getDuration()); + mBackgroundDimAnimator.addListener(getDimAnimatorListener()); + + dialogContainer.startAnimation(mDialogAnimation); + mBackgroundDimAnimator.start(); + } + + /** + * Cancels all animations and resets the state of the controller. + */ + void cancelAnimation() { + if (mDialogAnimation != null) { + mDialogAnimation.cancel(); + mDialogAnimation = null; + } + if (mBackgroundDimAnimator != null) { + mBackgroundDimAnimator.cancel(); + mBackgroundDimAnimator = null; + } + } + + private Animation loadAnimation(int animAttr) { + Animation animation = mTransitionAnimation.loadAnimationAttr(mPackageName, mAnimStyleResId, + animAttr, /* translucent= */ false); + if (animation == null) { + Log.e(TAG, "Failed to load animation " + animAttr); + } + return animation; + } + + private Animation.AnimationListener getAnimationListener(Runnable startCallback, + Runnable endCallback) { + return new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + startCallback.run(); + } + + @Override + public void onAnimationEnd(Animation animation) { + endCallback.run(); + } + + @Override + public void onAnimationRepeat(Animation animation) {} + }; + } + + private AnimatorListenerAdapter getDimAnimatorListener() { + return new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mBackgroundDimAnimator = null; + } + }; + } + + private static Animator getAlphaAnimator( + Drawable drawable, int endAlpha, long duration) { + Animator animator = ObjectAnimator.ofInt(drawable, DRAWABLE_ALPHA, endAlpha); + animator.setDuration(duration); + return animator; + } + + private static final Property DRAWABLE_ALPHA = new IntProperty( + "alpha") { + @Override + public void setValue(Drawable object, int value) { + object.setAlpha(value); + } + + @Override + public Integer get(Drawable object) { + return object.getAlpha(); + } + }; +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java index b045a4af4aacb..b22b829eebd8f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduDialogLayout.java @@ -17,7 +17,9 @@ package com.android.wm.shell.compatui.letterboxedu; import android.content.Context; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.view.View; import android.widget.FrameLayout; import com.android.wm.shell.R; @@ -33,9 +35,11 @@ class LetterboxEduDialogLayout extends FrameLayout { // The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque). // 204 is simply 255 * 0.8. - private static final int BACKGROUND_DIM_ALPHA = 204; + static final int BACKGROUND_DIM_ALPHA = 204; private LetterboxEduWindowManager mWindowManager; + private View mDialogContainer; + private Drawable mBackgroundDim; public LetterboxEduDialogLayout(Context context) { this(context, null); @@ -58,6 +62,14 @@ class LetterboxEduDialogLayout extends FrameLayout { mWindowManager = windowManager; } + View getDialogContainer() { + return mDialogContainer; + } + + Drawable getBackgroundDim() { + return mBackgroundDim; + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -77,12 +89,15 @@ class LetterboxEduDialogLayout extends FrameLayout { setOnClickListener(view -> callback.run()); // We add a no-op on-click listener to the dialog container so that clicks on it won't // propagate to the listener of the layout (which represents the background dim). - findViewById(R.id.letterbox_education_dialog_container).setOnClickListener(view -> {}); + mDialogContainer.setOnClickListener(view -> {}); } @Override protected void onFinishInflate() { super.onFinishInflate(); - getBackground().mutate().setAlpha(BACKGROUND_DIM_ALPHA); + mDialogContainer = findViewById(R.id.letterbox_education_dialog_container); + mBackgroundDim = getBackground().mutate(); + // Set the alpha of the background dim to 0 for enter animation. + mBackgroundDim.setAlpha(0); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java index e9ffca746a58a..d5aefb1a7e5c8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduWindowManager.java @@ -55,6 +55,8 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { */ private final SharedPreferences mSharedPreferences; + private final LetterboxEduAnimationController mAnimationController; + // Remember the last reported state in case visibility changes due to keyguard or IME updates. private boolean mEligibleForLetterboxEducation; @@ -69,6 +71,7 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { super(context, taskInfo, syncQueue, taskListener, displayLayout); mOnDismissCallback = onDismissCallback; mEligibleForLetterboxEducation = taskInfo.topActivityEligibleForLetterboxEducation; + mAnimationController = new LetterboxEduAnimationController(context); mSharedPreferences = mContext.getSharedPreferences(HAS_SEEN_LETTERBOX_EDUCATION_PREF_NAME, Context.MODE_PRIVATE); } @@ -101,7 +104,9 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { setSeenLetterboxEducation(); mLayout = inflateLayout(); mLayout.inject(this); - mLayout.setDismissOnClickListener(this::onDismiss); + + mAnimationController.startEnterAnimation(mLayout, /* endCallback= */ + this::setDismissOnClickListener); return mLayout; } @@ -111,9 +116,24 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract { R.layout.letterbox_education_dialog_layout, null); } + private void setDismissOnClickListener() { + if (mLayout == null) { + return; + } + mLayout.setDismissOnClickListener(this::onDismiss); + } + private void onDismiss() { - release(); - mOnDismissCallback.run(); + mAnimationController.startExitAnimation(mLayout, () -> { + release(); + mOnDismissCallback.run(); + }); + } + + @Override + public void release() { + mAnimationController.cancelAnimation(); + super.release(); } @Override