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