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