1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.wm.shell.startingsurface;
17 
18 import static android.view.View.GONE;
19 
20 import static com.android.internal.jank.InteractionJankMonitor.CUJ_SPLASHSCREEN_EXIT_ANIM;
21 
22 import android.animation.Animator;
23 import android.content.Context;
24 import android.graphics.Rect;
25 import android.util.Slog;
26 import android.view.SurfaceControl;
27 import android.view.View;
28 import android.window.SplashScreenView;
29 
30 import com.android.internal.jank.InteractionJankMonitor;
31 import com.android.wm.shell.R;
32 import com.android.wm.shell.common.TransactionPool;
33 
34 /**
35  * Default animation for exiting the splash screen window.
36  * @hide
37  */
38 public class SplashScreenExitAnimation implements Animator.AnimatorListener {
39     private static final boolean DEBUG_EXIT_ANIMATION = false;
40     private static final String TAG = StartingWindowController.TAG;
41 
42     private final SurfaceControl mFirstWindowSurface;
43     private final Rect mFirstWindowFrame = new Rect();
44     private final SplashScreenView mSplashScreenView;
45     private final int mMainWindowShiftLength;
46     private final int mIconFadeOutDuration;
47     private final int mAppRevealDelay;
48     private final int mAppRevealDuration;
49     @SplashScreenExitAnimationUtils.ExitAnimationType
50     private final int mAnimationType;
51     private final int mAnimationDuration;
52     private final float mIconStartAlpha;
53     private final float mBrandingStartAlpha;
54     private final TransactionPool mTransactionPool;
55     // TODO(b/261167708): Clean enter animation code after moving Letterbox code to Shell
56     private final float mRoundedCornerRadius;
57 
58     private Runnable mFinishCallback;
59 
SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash, Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish, float roundedCornerRadius)60     SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash,
61             Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish,
62             float roundedCornerRadius) {
63         mSplashScreenView = view;
64         mFirstWindowSurface = leash;
65         mRoundedCornerRadius = roundedCornerRadius;
66         if (frame != null) {
67             mFirstWindowFrame.set(frame);
68         }
69 
70         View iconView = view.getIconView();
71 
72         // If the icon and the background are invisible, don't animate it
73         if (iconView == null || iconView.getLayoutParams().width == 0
74                 || iconView.getLayoutParams().height == 0) {
75             mIconFadeOutDuration = 0;
76             mIconStartAlpha = 0;
77             mBrandingStartAlpha = 0;
78             mAppRevealDelay = 0;
79         } else {
80             iconView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
81             // The branding view could only exists when the icon is present.
82             final View brandingView = view.getBrandingView();
83             if (brandingView != null) {
84                 mBrandingStartAlpha = brandingView.getAlpha();
85             } else {
86                 mBrandingStartAlpha = 0;
87             }
88             mIconFadeOutDuration = context.getResources().getInteger(
89                     R.integer.starting_window_app_reveal_icon_fade_out_duration);
90             mAppRevealDelay = context.getResources().getInteger(
91                     R.integer.starting_window_app_reveal_anim_delay);
92             mIconStartAlpha = iconView.getAlpha();
93         }
94         mAppRevealDuration = context.getResources().getInteger(
95                 R.integer.starting_window_app_reveal_anim_duration);
96         mAnimationType = context.getResources().getInteger(
97                 R.integer.starting_window_exit_animation_type);
98         mAnimationDuration = Math.max(mIconFadeOutDuration, mAppRevealDelay + mAppRevealDuration);
99         mMainWindowShiftLength = mainWindowShiftLength;
100         mFinishCallback = handleFinish;
101         mTransactionPool = pool;
102     }
103 
startAnimations()104     void startAnimations() {
105         SplashScreenExitAnimationUtils.startAnimations(mAnimationType, mSplashScreenView,
106                 mFirstWindowSurface, mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame,
107                 mAnimationDuration, mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha,
108                 mAppRevealDelay, mAppRevealDuration, this, mRoundedCornerRadius);
109     }
110 
reset()111     private void reset() {
112         if (DEBUG_EXIT_ANIMATION) {
113             Slog.v(TAG, "vanish animation finished");
114         }
115 
116         if (mSplashScreenView.isAttachedToWindow()) {
117             mSplashScreenView.setVisibility(GONE);
118             if (mFinishCallback != null) {
119                 mFinishCallback.run();
120                 mFinishCallback = null;
121             }
122         }
123     }
124 
125     @Override
onAnimationStart(Animator animation)126     public void onAnimationStart(Animator animation) {
127         InteractionJankMonitor.getInstance().begin(mSplashScreenView, CUJ_SPLASHSCREEN_EXIT_ANIM);
128     }
129 
130     @Override
onAnimationEnd(Animator animation)131     public void onAnimationEnd(Animator animation) {
132         reset();
133         InteractionJankMonitor.getInstance().end(CUJ_SPLASHSCREEN_EXIT_ANIM);
134     }
135 
136     @Override
onAnimationCancel(Animator animation)137     public void onAnimationCancel(Animator animation) {
138         reset();
139         InteractionJankMonitor.getInstance().cancel(CUJ_SPLASHSCREEN_EXIT_ANIM);
140     }
141 
142     @Override
onAnimationRepeat(Animator animation)143     public void onAnimationRepeat(Animator animation) {
144         // ignore
145     }
146 }
147