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 android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 19 20 import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks; 21 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; 22 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; 23 import static com.android.launcher3.util.NavigationMode.NO_BUTTON; 24 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS; 25 import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED; 26 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED; 27 import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED; 28 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION; 29 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; 30 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED; 31 32 import android.app.ActivityManager; 33 import android.app.ActivityOptions; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.os.SystemProperties; 37 import android.util.Log; 38 import android.view.RemoteAnimationTarget; 39 40 import androidx.annotation.NonNull; 41 import androidx.annotation.Nullable; 42 import androidx.annotation.UiThread; 43 44 import com.android.internal.util.ArrayUtils; 45 import com.android.launcher3.Utilities; 46 import com.android.launcher3.config.FeatureFlags; 47 import com.android.launcher3.util.DisplayController; 48 import com.android.quickstep.util.ActiveGestureLog; 49 import com.android.quickstep.util.SystemUiFlagUtils; 50 import com.android.quickstep.views.RecentsView; 51 import com.android.systemui.shared.recents.model.ThumbnailData; 52 import com.android.systemui.shared.system.ActivityManagerWrapper; 53 import com.android.systemui.shared.system.QuickStepContract; 54 import com.android.systemui.shared.system.TaskStackChangeListener; 55 import com.android.systemui.shared.system.TaskStackChangeListeners; 56 57 import java.io.PrintWriter; 58 import java.util.HashMap; 59 60 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener { 61 public static final boolean ENABLE_SHELL_TRANSITIONS = true; 62 public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS 63 && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false); 64 65 private final Context mCtx; 66 private RecentsAnimationController mController; 67 private RecentsAnimationCallbacks mCallbacks; 68 private RecentsAnimationTargets mTargets; 69 // Temporary until we can hook into gesture state events 70 private GestureState mLastGestureState; 71 private RemoteAnimationTarget[] mLastAppearedTaskTargets; 72 private Runnable mLiveTileCleanUpHandler; 73 74 private boolean mRecentsAnimationStartPending = false; 75 private boolean mShouldIgnoreMotionEvents = false; 76 77 private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() { 78 @Override 79 public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task, 80 boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) { 81 if (mLastGestureState == null) { 82 TaskStackChangeListeners.getInstance().unregisterTaskStackListener( 83 mLiveTileRestartListener); 84 return; 85 } 86 BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface(); 87 if (containerInterface.isInLiveTileMode() 88 && containerInterface.getCreatedContainer() != null) { 89 RecentsView recentsView = containerInterface.getCreatedContainer() 90 .getOverviewPanel(); 91 if (recentsView != null) { 92 recentsView.launchSideTaskInLiveTileModeForRestartedApp(task.taskId); 93 TaskStackChangeListeners.getInstance().unregisterTaskStackListener( 94 mLiveTileRestartListener); 95 } 96 } 97 } 98 }; 99 TaskAnimationManager(Context ctx)100 TaskAnimationManager(Context ctx) { 101 mCtx = ctx; 102 } 103 /** 104 * Preloads the recents animation. 105 */ preloadRecentsAnimation(Intent intent)106 public void preloadRecentsAnimation(Intent intent) { 107 // Pass null animation handler to indicate this start is for preloading 108 UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance() 109 .startRecentsActivity(intent, 0, null, null, null)); 110 } 111 shouldIgnoreMotionEvents()112 boolean shouldIgnoreMotionEvents() { 113 return mShouldIgnoreMotionEvents; 114 } 115 notifyNewGestureStart()116 void notifyNewGestureStart() { 117 // If mRecentsAnimationStartPending is true at the beginning of a gesture, block all motion 118 // events for this new gesture so that this new gesture does not interfere with the 119 // previously-requested recents animation. Otherwise, clean up mShouldIgnoreMotionEvents. 120 // NOTE: this can lead to misleading logs 121 mShouldIgnoreMotionEvents = mRecentsAnimationStartPending; 122 } 123 124 /** 125 * Starts a new recents animation for the activity with the given {@param intent}. 126 */ 127 @UiThread startRecentsAnimation(@onNull GestureState gestureState, Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener)128 public RecentsAnimationCallbacks startRecentsAnimation(@NonNull GestureState gestureState, 129 Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) { 130 ActiveGestureLog.INSTANCE.addLog( 131 /* event= */ "startRecentsAnimation", 132 /* gestureEvent= */ START_RECENTS_ANIMATION); 133 // Notify if recents animation is still running 134 if (mController != null) { 135 String msg = "New recents animation started before old animation completed"; 136 if (FeatureFlags.IS_STUDIO_BUILD) { 137 throw new IllegalArgumentException(msg); 138 } else { 139 Log.e("TaskAnimationManager", msg, new Exception()); 140 } 141 } 142 // But force-finish it anyways 143 finishRunningRecentsAnimation(false /* toHome */, true /* forceFinish */, 144 null /* forceFinishCb */); 145 146 if (mCallbacks != null) { 147 // If mCallbacks still != null, that means we are getting this startRecentsAnimation() 148 // before the previous one got onRecentsAnimationStart(). In that case, cleanup the 149 // previous animation so it doesn't mess up/listen to state changes in this animation. 150 cleanUpRecentsAnimation(mCallbacks); 151 } 152 153 final BaseContainerInterface containerInterface = gestureState.getContainerInterface(); 154 mLastGestureState = gestureState; 155 RecentsAnimationCallbacks newCallbacks = new RecentsAnimationCallbacks( 156 SystemUiProxy.INSTANCE.get(mCtx), containerInterface.allowMinimizeSplitScreen()); 157 mCallbacks = newCallbacks; 158 mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() { 159 @Override 160 public void onRecentsAnimationStart(RecentsAnimationController controller, 161 RecentsAnimationTargets targets) { 162 if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) { 163 ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString( 164 "TaskAnimationManager.startRecentsAnimation(onRecentsAnimationStart): ") 165 .append("Setting mRecentsAnimationStartPending = false")); 166 mRecentsAnimationStartPending = false; 167 } 168 if (mCallbacks == null) { 169 // It's possible for the recents animation to have finished and be cleaned up 170 // by the time we process the start callback, and in that case, just we can skip 171 // handling this call entirely 172 return; 173 } 174 mController = controller; 175 mTargets = targets; 176 // TODO(b/236226779): We can probably get away w/ setting mLastAppearedTaskTargets 177 // to all appeared targets directly vs just looking at running ones 178 int[] runningTaskIds = mLastGestureState.getRunningTaskIds(targets.apps.length > 1); 179 mLastAppearedTaskTargets = new RemoteAnimationTarget[runningTaskIds.length]; 180 for (int i = 0; i < runningTaskIds.length; i++) { 181 RemoteAnimationTarget task = mTargets.findTask(runningTaskIds[i]); 182 mLastAppearedTaskTargets[i] = task; 183 } 184 mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets); 185 186 if (ENABLE_SHELL_TRANSITIONS && mTargets.hasRecents 187 // The filtered (MODE_CLOSING) targets only contain 1 home activity. 188 && mTargets.apps.length == 1 189 && mTargets.apps[0].windowConfiguration.getActivityType() 190 == ACTIVITY_TYPE_HOME) { 191 // This is launching RecentsActivity on top of a 3p launcher. There are no 192 // other apps need to keep visible so finish the animating state after the 193 // enter animation of overview is done. Then 3p launcher can be stopped. 194 mLastGestureState.runOnceAtState(STATE_END_TARGET_ANIMATION_FINISHED, () -> { 195 if (mLastGestureState != gestureState) return; 196 // Only finish if the end target is RECENTS. Otherwise, if the target is 197 // NEW_TASK, startActivityFromRecents will be skipped. 198 if (mLastGestureState.getEndTarget() == RECENTS) { 199 finishRunningRecentsAnimation(false /* toHome */, 200 true /* forceFinish */, null /* forceFinishCb */); 201 } 202 }); 203 } 204 } 205 206 @Override 207 public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) { 208 if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) { 209 ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString( 210 "TaskAnimationManager.startRecentsAnimation") 211 .append("(onRecentsAnimationCanceled): ") 212 .append("Setting mRecentsAnimationStartPending = false")); 213 mRecentsAnimationStartPending = false; 214 } 215 cleanUpRecentsAnimation(newCallbacks); 216 } 217 218 @Override 219 public void onRecentsAnimationFinished(RecentsAnimationController controller) { 220 if (enableHandleDelayedGestureCallbacks() && mRecentsAnimationStartPending) { 221 ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString( 222 "TaskAnimationManager.startRecentsAnimation") 223 .append("(onRecentsAnimationFinished): ") 224 .append("Setting mRecentsAnimationStartPending = false")); 225 mRecentsAnimationStartPending = false; 226 } 227 cleanUpRecentsAnimation(newCallbacks); 228 } 229 230 private boolean isNonRecentsStartedTasksAppeared( 231 RemoteAnimationTarget[] appearedTaskTargets) { 232 // For example, right after swiping from task X to task Y (e.g. from 233 // AbsSwipeUpHandler#startNewTask), and then task Y starts X immediately 234 // (e.g. in Y's onResume). The case will be: lastStartedTask=Y and appearedTask=X. 235 return mLastGestureState.getEndTarget() == GestureState.GestureEndTarget.NEW_TASK 236 && ArrayUtils.find(appearedTaskTargets, 237 mLastGestureState.mLastStartedTaskIdPredicate) == null; 238 } 239 240 @Override 241 public void onTasksAppeared(RemoteAnimationTarget[] appearedTaskTargets) { 242 RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0]; 243 BaseContainerInterface containerInterface = 244 mLastGestureState.getContainerInterface(); 245 246 for (RemoteAnimationTarget compat : appearedTaskTargets) { 247 if (compat.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME 248 && containerInterface.getCreatedContainer() instanceof RecentsActivity 249 && DisplayController.getNavigationMode(mCtx) != NO_BUTTON) { 250 // The only time we get onTasksAppeared() in button navigation with a 251 // 3p launcher is if the user goes to overview first, and in this case we 252 // can immediately finish the transition 253 RecentsView recentsView = 254 containerInterface.getCreatedContainer().getOverviewPanel(); 255 if (recentsView != null) { 256 recentsView.finishRecentsAnimation(true, null); 257 } 258 return; 259 } 260 } 261 262 RemoteAnimationTarget[] nonAppTargets = ENABLE_SHELL_TRANSITIONS 263 ? null : SystemUiProxy.INSTANCE.get(mCtx).onStartingSplitLegacy( 264 appearedTaskTargets); 265 if (nonAppTargets == null) { 266 nonAppTargets = new RemoteAnimationTarget[0]; 267 } 268 if ((containerInterface.isInLiveTileMode() 269 || mLastGestureState.getEndTarget() == RECENTS 270 || isNonRecentsStartedTasksAppeared(appearedTaskTargets)) 271 && containerInterface.getCreatedContainer() != null) { 272 RecentsView recentsView = 273 containerInterface.getCreatedContainer().getOverviewPanel(); 274 if (recentsView != null) { 275 ActiveGestureLog.INSTANCE.addLog( 276 new ActiveGestureLog.CompoundString("Launching side task id=") 277 .append(appearedTaskTarget.taskId)); 278 recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, 279 appearedTaskTargets, 280 new RemoteAnimationTarget[0] /* wallpaper */, 281 nonAppTargets /* nonApps */); 282 return; 283 } else { 284 ActiveGestureLog.INSTANCE.addLog("Unable to launch side task (no recents)"); 285 } 286 } else if (nonAppTargets.length > 0) { 287 TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets /* nonApps */, 288 true /*shown*/, null /* animatorHandler */); 289 } 290 if (mController != null) { 291 if (mLastAppearedTaskTargets != null) { 292 for (RemoteAnimationTarget lastTarget : mLastAppearedTaskTargets) { 293 for (RemoteAnimationTarget appearedTarget : appearedTaskTargets) { 294 if (lastTarget != null && 295 appearedTarget.taskId != lastTarget.taskId) { 296 mController.removeTaskTarget(lastTarget.taskId); 297 } 298 } 299 } 300 } 301 mLastAppearedTaskTargets = appearedTaskTargets; 302 mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets); 303 } 304 } 305 306 @Override 307 public boolean onSwitchToScreenshot(Runnable onFinished) { 308 if (!containerInterface.isInLiveTileMode() 309 || containerInterface.getCreatedContainer() == null) { 310 // No need to switch since tile is already a screenshot. 311 onFinished.run(); 312 } else { 313 final RecentsView recentsView = 314 containerInterface.getCreatedContainer().getOverviewPanel(); 315 if (recentsView != null) { 316 recentsView.switchToScreenshot(onFinished); 317 } else { 318 onFinished.run(); 319 } 320 } 321 return true; 322 } 323 }); 324 final long eventTime = gestureState.getSwipeUpStartTimeMs(); 325 mCallbacks.addListener(gestureState); 326 mCallbacks.addListener(listener); 327 328 if (ENABLE_SHELL_TRANSITIONS) { 329 final ActivityOptions options = ActivityOptions.makeBasic(); 330 // Use regular (non-transient) launch for all apps page to control IME. 331 if (!containerInterface.allowAllAppsFromOverview()) { 332 options.setTransientLaunch(); 333 } 334 options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime); 335 mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.get(mCtx) 336 .startRecentsActivity(intent, options, mCallbacks); 337 if (enableHandleDelayedGestureCallbacks()) { 338 ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString( 339 "TaskAnimationManager.startRecentsAnimation(shell transition path): ") 340 .append("Setting mRecentsAnimationStartPending = ") 341 .append(mRecentsAnimationStartPending)); 342 } 343 } else { 344 UI_HELPER_EXECUTOR.execute( 345 () -> ActivityManagerWrapper.getInstance().startRecentsActivity( 346 intent, 347 eventTime, 348 mCallbacks, 349 result -> { 350 if (enableHandleDelayedGestureCallbacks()) { 351 ActiveGestureLog.INSTANCE.addLog( 352 new ActiveGestureLog.CompoundString( 353 "TaskAnimationManager.startRecentsAnimation") 354 .append("(legacy path): Setting ") 355 .append("mRecentsAnimationStartPending = ") 356 .append(result)); 357 } 358 mRecentsAnimationStartPending = result; 359 }, 360 MAIN_EXECUTOR.getHandler())); 361 } 362 gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED); 363 return mCallbacks; 364 } 365 366 /** 367 * Continues the existing running recents animation for a new gesture. 368 */ continueRecentsAnimation(GestureState gestureState)369 public RecentsAnimationCallbacks continueRecentsAnimation(GestureState gestureState) { 370 ActiveGestureLog.INSTANCE.addLog(/* event= */ "continueRecentsAnimation"); 371 mCallbacks.removeListener(mLastGestureState); 372 mLastGestureState = gestureState; 373 mCallbacks.addListener(gestureState); 374 gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED 375 | STATE_RECENTS_ANIMATION_STARTED); 376 gestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets); 377 return mCallbacks; 378 } 379 onSystemUiFlagsChanged(@uickStepContract.SystemUiStateFlags long lastSysUIFlags, @QuickStepContract.SystemUiStateFlags long newSysUIFlags)380 public void onSystemUiFlagsChanged(@QuickStepContract.SystemUiStateFlags long lastSysUIFlags, 381 @QuickStepContract.SystemUiStateFlags long newSysUIFlags) { 382 long isShadeExpandedFlagMask = 383 SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED; 384 boolean wasExpanded = hasAnyFlag(lastSysUIFlags, isShadeExpandedFlagMask); 385 boolean isExpanded = hasAnyFlag(newSysUIFlags, isShadeExpandedFlagMask); 386 if (wasExpanded != isExpanded && isExpanded) { 387 // End live tile when expanding the notification panel for the first time from 388 // overview. 389 if (endLiveTile()) { 390 return; 391 } 392 } 393 394 boolean wasLocked = SystemUiFlagUtils.isLocked(lastSysUIFlags); 395 boolean isLocked = SystemUiFlagUtils.isLocked(newSysUIFlags); 396 if (wasLocked != isLocked && isLocked) { 397 // Finish the running recents animation when locking the device. 398 finishRunningRecentsAnimation( 399 mController != null && mController.getFinishTargetIsLauncher()); 400 } 401 } 402 hasAnyFlag(long flags, long flagMask)403 private boolean hasAnyFlag(long flags, long flagMask) { 404 return (flags & flagMask) != 0; 405 } 406 407 /** 408 * Switches the {@link RecentsView} to screenshot if in live tile mode. 409 * 410 * @return true iff the {@link RecentsView} was in live tile mode and was switched to screenshot 411 */ endLiveTile()412 public boolean endLiveTile() { 413 if (mLastGestureState == null) { 414 return false; 415 } 416 BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface(); 417 if (!containerInterface.isInLiveTileMode() 418 || containerInterface.getCreatedContainer() == null) { 419 return false; 420 } 421 RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel(); 422 if (recentsView == null) { 423 return false; 424 } 425 recentsView.switchToScreenshot(null, () -> recentsView.finishRecentsAnimation( 426 true /* toRecents */, false /* shouldPip */, null)); 427 return true; 428 } 429 setLiveTileCleanUpHandler(Runnable cleanUpHandler)430 public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) { 431 mLiveTileCleanUpHandler = cleanUpHandler; 432 } 433 enableLiveTileRestartListener()434 public void enableLiveTileRestartListener() { 435 TaskStackChangeListeners.getInstance().registerTaskStackListener(mLiveTileRestartListener); 436 } 437 438 /** 439 * Finishes the running recents animation. 440 */ finishRunningRecentsAnimation(boolean toHome)441 public void finishRunningRecentsAnimation(boolean toHome) { 442 finishRunningRecentsAnimation(toHome, false /* forceFinish */, null /* forceFinishCb */); 443 } 444 445 /** 446 * Finishes the running recents animation. 447 * @param forceFinish will synchronously finish the controller 448 */ finishRunningRecentsAnimation(boolean toHome, boolean forceFinish, Runnable forceFinishCb)449 public void finishRunningRecentsAnimation(boolean toHome, boolean forceFinish, 450 Runnable forceFinishCb) { 451 if (mController != null) { 452 ActiveGestureLog.INSTANCE.addLog( 453 /* event= */ "finishRunningRecentsAnimation", toHome); 454 if (forceFinish) { 455 mController.finishController(toHome, forceFinishCb, false /* sendUserLeaveHint */, 456 true /* forceFinish */); 457 } else { 458 Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome 459 ? mController::finishAnimationToHome 460 : mController::finishAnimationToApp); 461 } 462 } 463 } 464 465 /** 466 * Used to notify a listener of the current recents animation state (used if the listener was 467 * not yet added to the callbacks at the point that the listener callbacks would have been 468 * made). 469 */ notifyRecentsAnimationState( RecentsAnimationCallbacks.RecentsAnimationListener listener)470 public void notifyRecentsAnimationState( 471 RecentsAnimationCallbacks.RecentsAnimationListener listener) { 472 if (isRecentsAnimationRunning()) { 473 listener.onRecentsAnimationStart(mController, mTargets); 474 } 475 // TODO: Do we actually need to report canceled/finished? 476 } 477 478 /** 479 * @return whether there is a recents animation running. 480 */ isRecentsAnimationRunning()481 public boolean isRecentsAnimationRunning() { 482 return mController != null; 483 } 484 485 /** 486 * Cleans up the recents animation entirely. 487 */ cleanUpRecentsAnimation(RecentsAnimationCallbacks targetCallbacks)488 private void cleanUpRecentsAnimation(RecentsAnimationCallbacks targetCallbacks) { 489 if (mCallbacks != targetCallbacks) { 490 ActiveGestureLog.INSTANCE.addLog( 491 /* event= */ "cleanUpRecentsAnimation skipped due to wrong callbacks"); 492 return; 493 } 494 ActiveGestureLog.INSTANCE.addLog(/* event= */ "cleanUpRecentsAnimation"); 495 if (mLiveTileCleanUpHandler != null) { 496 mLiveTileCleanUpHandler.run(); 497 mLiveTileCleanUpHandler = null; 498 } 499 TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mLiveTileRestartListener); 500 501 // Release all the target leashes 502 if (mTargets != null) { 503 mTargets.release(); 504 } 505 506 // Clean up all listeners to ensure we don't get subsequent callbacks 507 if (mCallbacks != null) { 508 mCallbacks.removeAllListeners(); 509 } 510 511 mController = null; 512 mCallbacks = null; 513 mTargets = null; 514 mLastGestureState = null; 515 mLastAppearedTaskTargets = null; 516 } 517 518 @Nullable getCurrentCallbacks()519 public RecentsAnimationCallbacks getCurrentCallbacks() { 520 return mCallbacks; 521 } 522 dump(String prefix, PrintWriter pw)523 public void dump(String prefix, PrintWriter pw) { 524 pw.println(prefix + "TaskAnimationManager:"); 525 526 if (enableHandleDelayedGestureCallbacks()) { 527 pw.println(prefix + "\tmRecentsAnimationStartPending=" + mRecentsAnimationStartPending); 528 pw.println(prefix + "\tmShouldIgnoreUpcomingGestures=" + mShouldIgnoreMotionEvents); 529 } 530 if (mController != null) { 531 mController.dump(prefix + '\t', pw); 532 } 533 if (mCallbacks != null) { 534 mCallbacks.dump(prefix + '\t', pw); 535 } 536 if (mTargets != null) { 537 mTargets.dump(prefix + '\t', pw); 538 } 539 if (mLastGestureState != null) { 540 mLastGestureState.dump(prefix + '\t', pw); 541 } 542 } 543 } 544