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