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