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