1 /*
2  * Copyright (C) 2019 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.quickstep;
17 
18 import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
19 
20 import android.annotation.TargetApi;
21 import android.app.ActivityManager;
22 import android.content.Intent;
23 import android.os.Build;
24 
25 import com.android.launcher3.statemanager.StatefulActivity;
26 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
27 import com.android.quickstep.util.ActiveGestureLog;
28 import com.android.systemui.shared.recents.model.ThumbnailData;
29 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
30 
31 import java.io.PrintWriter;
32 import java.util.ArrayList;
33 import java.util.HashSet;
34 import java.util.Set;
35 
36 /**
37  * Manages the state for an active system gesture, listens for events from the system and Launcher,
38  * and fires events when the states change.
39  */
40 @TargetApi(Build.VERSION_CODES.R)
41 public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationListener {
42 
43     /**
44      * Defines the end targets of a gesture and the associated state.
45      */
46     public enum GestureEndTarget {
47         HOME(true, ContainerType.WORKSPACE, false),
48 
49         RECENTS(true, ContainerType.TASKSWITCHER, true),
50 
51         NEW_TASK(false, ContainerType.APP, true),
52 
53         LAST_TASK(false, ContainerType.APP, true);
54 
GestureEndTarget(boolean isLauncher, int containerType, boolean recentsAttachedToAppWindow)55         GestureEndTarget(boolean isLauncher, int containerType,
56                 boolean recentsAttachedToAppWindow) {
57             this.isLauncher = isLauncher;
58             this.containerType = containerType;
59             this.recentsAttachedToAppWindow = recentsAttachedToAppWindow;
60         }
61 
62         /** Whether the target is in the launcher activity. Implicitly, if the end target is going
63          to Launcher, then we can not interrupt the animation to start another gesture. */
64         public final boolean isLauncher;
65         /** Used to log where the user ended up after the gesture ends */
66         public final int containerType;
67         /** Whether RecentsView should be attached to the window as we animate to this target */
68         public final boolean recentsAttachedToAppWindow;
69     }
70 
71     private static final String TAG = "GestureState";
72 
73     private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
74     public static final GestureState DEFAULT_STATE = new GestureState();
75 
76     private static int FLAG_COUNT = 0;
getFlagForIndex(String name)77     private static int getFlagForIndex(String name) {
78         if (DEBUG_STATES) {
79             STATE_NAMES.add(name);
80         }
81         int index = 1 << FLAG_COUNT;
82         FLAG_COUNT++;
83         return index;
84     }
85 
86     // Called when the end target as been set
87     public static final int STATE_END_TARGET_SET =
88             getFlagForIndex("STATE_END_TARGET_SET");
89 
90     // Called when the end target animation has finished
91     public static final int STATE_END_TARGET_ANIMATION_FINISHED =
92             getFlagForIndex("STATE_END_TARGET_ANIMATION_FINISHED");
93 
94     // Called when the recents animation has been requested to start
95     public static final int STATE_RECENTS_ANIMATION_INITIALIZED =
96             getFlagForIndex("STATE_RECENTS_ANIMATION_INITIALIZED");
97 
98     // Called when the recents animation is started and the TaskAnimationManager has been updated
99     // with the controller and targets
100     public static final int STATE_RECENTS_ANIMATION_STARTED =
101             getFlagForIndex("STATE_RECENTS_ANIMATION_STARTED");
102 
103     // Called when the recents animation is canceled
104     public static final int STATE_RECENTS_ANIMATION_CANCELED =
105             getFlagForIndex("STATE_RECENTS_ANIMATION_CANCELED");
106 
107     // Called when the recents animation finishes
108     public static final int STATE_RECENTS_ANIMATION_FINISHED =
109             getFlagForIndex("STATE_RECENTS_ANIMATION_FINISHED");
110 
111     // Always called when the recents animation ends (regardless of cancel or finish)
112     public static final int STATE_RECENTS_ANIMATION_ENDED =
113             getFlagForIndex("STATE_RECENTS_ANIMATION_ENDED");
114 
115     // Called when we create an overscroll window when swiping right to left on the most recent app
116     public static final int STATE_OVERSCROLL_WINDOW_CREATED =
117             getFlagForIndex("STATE_OVERSCROLL_WINDOW_CREATED");
118 
119     // Called when RecentsView stops scrolling and settles on a TaskView.
120     public static final int STATE_RECENTS_SCROLLING_FINISHED =
121             getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
122 
123     // Needed to interact with the current activity
124     private final Intent mHomeIntent;
125     private final Intent mOverviewIntent;
126     private final BaseActivityInterface mActivityInterface;
127     private final MultiStateCallback mStateCallback;
128     private final int mGestureId;
129 
130     private ActivityManager.RunningTaskInfo mRunningTask;
131     private GestureEndTarget mEndTarget;
132     private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
133     private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>();
134     private int mLastStartedTaskId = -1;
135 
GestureState(OverviewComponentObserver componentObserver, int gestureId)136     public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
137         mHomeIntent = componentObserver.getHomeIntent();
138         mOverviewIntent = componentObserver.getOverviewIntent();
139         mActivityInterface = componentObserver.getActivityInterface();
140         mStateCallback = new MultiStateCallback(STATE_NAMES.toArray(new String[0]));
141         mGestureId = gestureId;
142     }
143 
GestureState(GestureState other)144     public GestureState(GestureState other) {
145         mHomeIntent = other.mHomeIntent;
146         mOverviewIntent = other.mOverviewIntent;
147         mActivityInterface = other.mActivityInterface;
148         mStateCallback = other.mStateCallback;
149         mGestureId = other.mGestureId;
150         mRunningTask = other.mRunningTask;
151         mEndTarget = other.mEndTarget;
152         mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
153         mPreviouslyAppearedTaskIds = other.mPreviouslyAppearedTaskIds;
154         mLastStartedTaskId = other.mLastStartedTaskId;
155     }
156 
GestureState()157     public GestureState() {
158         // Do nothing, only used for initializing the gesture state prior to user unlock
159         mHomeIntent = new Intent();
160         mOverviewIntent = new Intent();
161         mActivityInterface = null;
162         mStateCallback = new MultiStateCallback(STATE_NAMES.toArray(new String[0]));
163         mGestureId = -1;
164     }
165 
166     /**
167      * @return whether the gesture state has the provided {@param stateMask} flags set.
168      */
hasState(int stateMask)169     public boolean hasState(int stateMask) {
170         return mStateCallback.hasStates(stateMask);
171     }
172 
173     /**
174      * Sets the given {@param stateFlag}s.
175      */
setState(int stateFlag)176     public void setState(int stateFlag) {
177         mStateCallback.setState(stateFlag);
178     }
179 
180     /**
181      * Adds a callback for when the states matching the given {@param stateMask} is set.
182      */
runOnceAtState(int stateMask, Runnable callback)183     public void runOnceAtState(int stateMask, Runnable callback) {
184         mStateCallback.runOnceAtState(stateMask, callback);
185     }
186 
187     /**
188      * @return the intent for the Home component.
189      */
getHomeIntent()190     public Intent getHomeIntent() {
191         return mHomeIntent;
192     }
193 
194     /**
195      * @return the intent for the Overview component.
196      */
getOverviewIntent()197     public Intent getOverviewIntent() {
198         return mOverviewIntent;
199     }
200 
201     /**
202      * @return the interface to the activity handing the UI updates for this gesture.
203      */
getActivityInterface()204     public <T extends StatefulActivity<?>> BaseActivityInterface<?, T> getActivityInterface() {
205         return mActivityInterface;
206     }
207 
208     /**
209      * @return the id for this particular gesture.
210      */
getGestureId()211     public int getGestureId() {
212         return mGestureId;
213     }
214 
215     /**
216      * @return the running task for this gesture.
217      */
getRunningTask()218     public ActivityManager.RunningTaskInfo getRunningTask() {
219         return mRunningTask;
220     }
221 
222     /**
223      * @return the running task id for this gesture.
224      */
getRunningTaskId()225     public int getRunningTaskId() {
226         return mRunningTask != null ? mRunningTask.taskId : -1;
227     }
228 
229     /**
230      * Updates the running task for the gesture to be the given {@param runningTask}.
231      */
updateRunningTask(ActivityManager.RunningTaskInfo runningTask)232     public void updateRunningTask(ActivityManager.RunningTaskInfo runningTask) {
233         mRunningTask = runningTask;
234     }
235 
236     /**
237      * Updates the last task that appeared during this gesture.
238      */
updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget)239     public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
240         mLastAppearedTaskTarget = lastAppearedTaskTarget;
241         if (lastAppearedTaskTarget != null) {
242             mPreviouslyAppearedTaskIds.add(lastAppearedTaskTarget.taskId);
243         }
244     }
245 
246     /**
247      * @return The id of the task that appeared during this gesture.
248      */
getLastAppearedTaskId()249     public int getLastAppearedTaskId() {
250         return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
251     }
252 
updatePreviouslyAppearedTaskIds(Set<Integer> previouslyAppearedTaskIds)253     public void updatePreviouslyAppearedTaskIds(Set<Integer> previouslyAppearedTaskIds) {
254         mPreviouslyAppearedTaskIds = previouslyAppearedTaskIds;
255     }
256 
getPreviouslyAppearedTaskIds()257     public Set<Integer> getPreviouslyAppearedTaskIds() {
258         return mPreviouslyAppearedTaskIds;
259     }
260 
261     /**
262      * Updates the last task that we started via startActivityFromRecents() during this gesture.
263      */
updateLastStartedTaskId(int lastStartedTaskId)264     public void updateLastStartedTaskId(int lastStartedTaskId) {
265         mLastStartedTaskId = lastStartedTaskId;
266     }
267 
268     /**
269      * @return The id of the task that was most recently started during this gesture, or -1 if
270      * no task has been started yet (i.e. we haven't settled on a new task).
271      */
getLastStartedTaskId()272     public int getLastStartedTaskId() {
273         return mLastStartedTaskId;
274     }
275 
276     /**
277      * @return the end target for this gesture (if known).
278      */
getEndTarget()279     public GestureEndTarget getEndTarget() {
280         return mEndTarget;
281     }
282 
283     /**
284      * Sets the end target of this gesture and immediately notifies the state changes.
285      */
setEndTarget(GestureEndTarget target)286     public void setEndTarget(GestureEndTarget target) {
287         setEndTarget(target, true /* isAtomic */);
288     }
289 
290     /**
291      * Sets the end target of this gesture, but if {@param isAtomic} is {@code false}, then the
292      * caller must explicitly set {@link #STATE_END_TARGET_ANIMATION_FINISHED} themselves.
293      */
setEndTarget(GestureEndTarget target, boolean isAtomic)294     public void setEndTarget(GestureEndTarget target, boolean isAtomic) {
295         mEndTarget = target;
296         mStateCallback.setState(STATE_END_TARGET_SET);
297         ActiveGestureLog.INSTANCE.addLog("setEndTarget " + mEndTarget);
298         if (isAtomic) {
299             mStateCallback.setState(STATE_END_TARGET_ANIMATION_FINISHED);
300         }
301     }
302 
303     /**
304      * @return whether the current gesture is still running a recents animation to a state in the
305      *         Launcher or Recents activity.
306      */
isRunningAnimationToLauncher()307     public boolean isRunningAnimationToLauncher() {
308         return isRecentsAnimationRunning() && mEndTarget != null && mEndTarget.isLauncher;
309     }
310 
311     /**
312      * @return whether the recents animation is started but not yet ended
313      */
isRecentsAnimationRunning()314     public boolean isRecentsAnimationRunning() {
315         return mStateCallback.hasStates(STATE_RECENTS_ANIMATION_INITIALIZED) &&
316                 !mStateCallback.hasStates(STATE_RECENTS_ANIMATION_ENDED);
317     }
318 
319     @Override
onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets)320     public void onRecentsAnimationStart(RecentsAnimationController controller,
321             RecentsAnimationTargets targets) {
322         mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED);
323     }
324 
325     @Override
onRecentsAnimationCanceled(ThumbnailData thumbnailData)326     public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
327         mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED);
328         mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
329     }
330 
331     @Override
onRecentsAnimationFinished(RecentsAnimationController controller)332     public void onRecentsAnimationFinished(RecentsAnimationController controller) {
333         mStateCallback.setState(STATE_RECENTS_ANIMATION_FINISHED);
334         mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
335     }
336 
dump(PrintWriter pw)337     public void dump(PrintWriter pw) {
338         pw.println("GestureState:");
339         pw.println("  gestureID=" + mGestureId);
340         pw.println("  runningTask=" + mRunningTask);
341         pw.println("  endTarget=" + mEndTarget);
342         pw.println("  lastAppearedTaskTargetId=" + getLastAppearedTaskId());
343         pw.println("  lastStartedTaskId=" + mLastStartedTaskId);
344         pw.println("  isRecentsAnimationRunning=" + isRecentsAnimationRunning());
345     }
346 }
347