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