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