1 /* 2 * Copyright (C) 2023 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 17 package com.android.wm.shell.back; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.res.Configuration; 22 import android.util.Log; 23 import android.util.SparseArray; 24 import android.window.BackNavigationInfo; 25 26 /** Registry for all types of default back animations */ 27 public class ShellBackAnimationRegistry { 28 private static final String TAG = "ShellBackPreview"; 29 30 private final SparseArray<BackAnimationRunner> mAnimationDefinition = new SparseArray<>(); 31 private ShellBackAnimation mDefaultCrossActivityAnimation; 32 private final ShellBackAnimation mCustomizeActivityAnimation; 33 private final ShellBackAnimation mCrossTaskAnimation; 34 ShellBackAnimationRegistry( @hellBackAnimation.CrossActivity @ullable ShellBackAnimation crossActivityAnimation, @ShellBackAnimation.CrossTask @Nullable ShellBackAnimation crossTaskAnimation, @ShellBackAnimation.DialogClose @Nullable ShellBackAnimation dialogCloseAnimation, @ShellBackAnimation.CustomizeActivity @Nullable ShellBackAnimation customizeActivityAnimation, @ShellBackAnimation.ReturnToHome @Nullable ShellBackAnimation defaultBackToHomeAnimation)35 public ShellBackAnimationRegistry( 36 @ShellBackAnimation.CrossActivity @Nullable ShellBackAnimation crossActivityAnimation, 37 @ShellBackAnimation.CrossTask @Nullable ShellBackAnimation crossTaskAnimation, 38 @ShellBackAnimation.DialogClose @Nullable ShellBackAnimation dialogCloseAnimation, 39 @ShellBackAnimation.CustomizeActivity @Nullable 40 ShellBackAnimation customizeActivityAnimation, 41 @ShellBackAnimation.ReturnToHome @Nullable 42 ShellBackAnimation defaultBackToHomeAnimation) { 43 if (crossActivityAnimation != null) { 44 mAnimationDefinition.set( 45 BackNavigationInfo.TYPE_CROSS_ACTIVITY, crossActivityAnimation.getRunner()); 46 } 47 if (crossTaskAnimation != null) { 48 mAnimationDefinition.set( 49 BackNavigationInfo.TYPE_CROSS_TASK, crossTaskAnimation.getRunner()); 50 } 51 if (dialogCloseAnimation != null) { 52 mAnimationDefinition.set( 53 BackNavigationInfo.TYPE_DIALOG_CLOSE, dialogCloseAnimation.getRunner()); 54 } 55 if (defaultBackToHomeAnimation != null) { 56 mAnimationDefinition.set( 57 BackNavigationInfo.TYPE_RETURN_TO_HOME, defaultBackToHomeAnimation.getRunner()); 58 } 59 60 mDefaultCrossActivityAnimation = crossActivityAnimation; 61 mCustomizeActivityAnimation = customizeActivityAnimation; 62 mCrossTaskAnimation = crossTaskAnimation; 63 64 // TODO(b/236760237): register dialog close animation when it's completed. 65 } 66 registerAnimation( @ackNavigationInfo.BackTargetType int type, @NonNull BackAnimationRunner runner)67 void registerAnimation( 68 @BackNavigationInfo.BackTargetType int type, @NonNull BackAnimationRunner runner) { 69 mAnimationDefinition.set(type, runner); 70 // Only happen in test 71 if (BackNavigationInfo.TYPE_CROSS_ACTIVITY == type) { 72 mDefaultCrossActivityAnimation = null; 73 } 74 } 75 unregisterAnimation(@ackNavigationInfo.BackTargetType int type)76 void unregisterAnimation(@BackNavigationInfo.BackTargetType int type) { 77 mAnimationDefinition.remove(type); 78 // Only happen in test 79 if (BackNavigationInfo.TYPE_CROSS_ACTIVITY == type) { 80 mDefaultCrossActivityAnimation = null; 81 } 82 } 83 84 /** 85 * Start the {@link BackAnimationRunner} associated with a back target type. 86 * 87 * @param type back target type 88 * @return true if the animation is started, false if animation is not found for that type. 89 */ startGesture(@ackNavigationInfo.BackTargetType int type)90 boolean startGesture(@BackNavigationInfo.BackTargetType int type) { 91 BackAnimationRunner runner = mAnimationDefinition.get(type); 92 if (runner == null) { 93 return false; 94 } 95 runner.startGesture(); 96 return true; 97 } 98 99 /** 100 * Cancel the {@link BackAnimationRunner} associated with a back target type. 101 * 102 * @param type back target type 103 * @return true if the animation is started, false if animation is not found for that type. 104 */ cancel(@ackNavigationInfo.BackTargetType int type)105 boolean cancel(@BackNavigationInfo.BackTargetType int type) { 106 BackAnimationRunner runner = mAnimationDefinition.get(type); 107 if (runner == null) { 108 return false; 109 } 110 runner.cancelAnimation(); 111 return true; 112 } 113 isAnimationCancelledOrNull(@ackNavigationInfo.BackTargetType int type)114 boolean isAnimationCancelledOrNull(@BackNavigationInfo.BackTargetType int type) { 115 BackAnimationRunner runner = mAnimationDefinition.get(type); 116 if (runner == null) { 117 return true; 118 } 119 return runner.isAnimationCancelled(); 120 } 121 isWaitingAnimation(@ackNavigationInfo.BackTargetType int type)122 boolean isWaitingAnimation(@BackNavigationInfo.BackTargetType int type) { 123 BackAnimationRunner runner = mAnimationDefinition.get(type); 124 if (runner == null) { 125 return false; 126 } 127 return runner.isWaitingAnimation(); 128 } 129 resetDefaultCrossActivity()130 void resetDefaultCrossActivity() { 131 if (mDefaultCrossActivityAnimation == null 132 || !mAnimationDefinition.contains(BackNavigationInfo.TYPE_CROSS_ACTIVITY)) { 133 return; 134 } 135 mAnimationDefinition.set( 136 BackNavigationInfo.TYPE_CROSS_ACTIVITY, mDefaultCrossActivityAnimation.getRunner()); 137 } 138 onConfigurationChanged(Configuration newConfig)139 void onConfigurationChanged(Configuration newConfig) { 140 if (mCustomizeActivityAnimation != null) { 141 mCustomizeActivityAnimation.onConfigurationChanged(newConfig); 142 } 143 if (mDefaultCrossActivityAnimation != null) { 144 mDefaultCrossActivityAnimation.onConfigurationChanged(newConfig); 145 } 146 if (mCrossTaskAnimation != null) { 147 mCrossTaskAnimation.onConfigurationChanged(newConfig); 148 } 149 } 150 getAnimationRunnerAndInit(BackNavigationInfo backNavigationInfo)151 BackAnimationRunner getAnimationRunnerAndInit(BackNavigationInfo backNavigationInfo) { 152 int type = backNavigationInfo.getType(); 153 // Initiate customized cross-activity animation, or fall back to cross activity animation 154 if (type == BackNavigationInfo.TYPE_CROSS_ACTIVITY && mAnimationDefinition.contains(type)) { 155 if (mCustomizeActivityAnimation != null 156 && mCustomizeActivityAnimation.prepareNextAnimation( 157 backNavigationInfo.getCustomAnimationInfo(), 0)) { 158 mAnimationDefinition.get(type).resetWaitingAnimation(); 159 mAnimationDefinition.set( 160 BackNavigationInfo.TYPE_CROSS_ACTIVITY, 161 mCustomizeActivityAnimation.getRunner()); 162 } else if (mDefaultCrossActivityAnimation != null) { 163 mDefaultCrossActivityAnimation.prepareNextAnimation(null, 164 backNavigationInfo.getLetterboxColor()); 165 } 166 } 167 BackAnimationRunner runner = mAnimationDefinition.get(type); 168 if (runner == null) { 169 Log.e( 170 TAG, 171 "Animation didn't be defined for type " 172 + BackNavigationInfo.typeToString(type)); 173 } 174 return runner; 175 } 176 } 177