1 /* 2 * Copyright (C) 2018 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 17 package com.android.server.wm; 18 19 import static android.app.ActivityManager.START_TASK_TO_FRONT; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 23 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 24 import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; 25 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 26 27 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS; 28 import static com.android.server.wm.ActivityRecord.State.STOPPED; 29 import static com.android.server.wm.ActivityRecord.State.STOPPING; 30 import static com.android.server.wm.ActivityTaskSupervisor.PRESERVE_WINDOWS; 31 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; 32 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; 33 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; 34 import static com.android.server.wm.TaskDisplayArea.getRootTaskAbove; 35 36 import android.annotation.Nullable; 37 import android.app.ActivityOptions; 38 import android.content.ComponentName; 39 import android.content.Intent; 40 import android.os.RemoteException; 41 import android.os.Trace; 42 import android.util.Slog; 43 import android.view.IRecentsAnimationRunner; 44 45 import com.android.internal.protolog.common.ProtoLog; 46 import com.android.internal.util.function.pooled.PooledLambda; 47 import com.android.internal.util.function.pooled.PooledPredicate; 48 import com.android.server.wm.ActivityMetricsLogger.LaunchingState; 49 import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; 50 import com.android.server.wm.TaskDisplayArea.OnRootTaskOrderChangedListener; 51 52 /** 53 * Manages the recents animation, including the reordering of the root tasks for the transition and 54 * cleanup. See {@link com.android.server.wm.RecentsAnimationController}. 55 */ 56 class RecentsAnimation implements RecentsAnimationCallbacks, OnRootTaskOrderChangedListener { 57 private static final String TAG = RecentsAnimation.class.getSimpleName(); 58 59 private final ActivityTaskManagerService mService; 60 private final ActivityTaskSupervisor mTaskSupervisor; 61 private final ActivityStartController mActivityStartController; 62 private final WindowManagerService mWindowManager; 63 private final TaskDisplayArea mDefaultTaskDisplayArea; 64 private final Intent mTargetIntent; 65 private final ComponentName mRecentsComponent; 66 private final @Nullable String mRecentsFeatureId; 67 private final int mRecentsUid; 68 private final @Nullable WindowProcessController mCaller; 69 private final int mUserId; 70 private final int mTargetActivityType; 71 72 /** 73 * The activity which has been launched behind. We need to remember the activity because the 74 * target root task may have other activities, then we are able to restore the launch-behind 75 * state for the exact activity. 76 */ 77 private ActivityRecord mLaunchedTargetActivity; 78 79 // The root task to restore the target root task behind when the animation is finished 80 private Task mRestoreTargetBehindRootTask; 81 RecentsAnimation(ActivityTaskManagerService atm, ActivityTaskSupervisor taskSupervisor, ActivityStartController activityStartController, WindowManagerService wm, Intent targetIntent, ComponentName recentsComponent, @Nullable String recentsFeatureId, int recentsUid, @Nullable WindowProcessController caller)82 RecentsAnimation(ActivityTaskManagerService atm, ActivityTaskSupervisor taskSupervisor, 83 ActivityStartController activityStartController, WindowManagerService wm, 84 Intent targetIntent, ComponentName recentsComponent, @Nullable String recentsFeatureId, 85 int recentsUid, @Nullable WindowProcessController caller) { 86 mService = atm; 87 mTaskSupervisor = taskSupervisor; 88 mDefaultTaskDisplayArea = mService.mRootWindowContainer.getDefaultTaskDisplayArea(); 89 mActivityStartController = activityStartController; 90 mWindowManager = wm; 91 mTargetIntent = targetIntent; 92 mRecentsComponent = recentsComponent; 93 mRecentsFeatureId = recentsFeatureId; 94 mRecentsUid = recentsUid; 95 mCaller = caller; 96 mUserId = atm.getCurrentUserId(); 97 mTargetActivityType = targetIntent.getComponent() != null 98 && recentsComponent.equals(targetIntent.getComponent()) 99 ? ACTIVITY_TYPE_RECENTS 100 : ACTIVITY_TYPE_HOME; 101 } 102 103 /** 104 * Starts the recents activity in background without animation if the record doesn't exist or 105 * the client isn't launched. If the recents activity is already alive, ensure its configuration 106 * is updated to the current one. 107 */ preloadRecentsActivity()108 void preloadRecentsActivity() { 109 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Preload recents with %s", 110 mTargetIntent); 111 Task targetRootTask = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, 112 mTargetActivityType); 113 ActivityRecord targetActivity = getTargetActivity(targetRootTask); 114 if (targetActivity != null) { 115 if (targetActivity.isVisibleRequested() || targetActivity.isTopRunningActivity()) { 116 // The activity is ready. 117 return; 118 } 119 if (targetActivity.attachedToProcess()) { 120 // The activity may be relaunched if it cannot handle the current configuration 121 // changes. The activity will be paused state if it is relaunched, otherwise it 122 // keeps the original stopped state. 123 targetActivity.ensureActivityConfiguration(0 /* globalChanges */, 124 false /* preserveWindow */, true /* ignoreVisibility */); 125 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Updated config=%s", 126 targetActivity.getConfiguration()); 127 } 128 } else if (mDefaultTaskDisplayArea.getActivity( 129 ActivityRecord::occludesParent, false /* traverseTopToBottom */) == null) { 130 // Skip because none of above activities can occlude the target activity. The preload 131 // should be done silently in background without being visible. 132 return; 133 } else { 134 // Create the activity record. Because the activity is invisible, this doesn't really 135 // start the client. 136 startRecentsActivityInBackground("preloadRecents"); 137 targetRootTask = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, 138 mTargetActivityType); 139 targetActivity = getTargetActivity(targetRootTask); 140 if (targetActivity == null) { 141 Slog.w(TAG, "Cannot start " + mTargetIntent); 142 return; 143 } 144 } 145 146 if (!targetActivity.attachedToProcess()) { 147 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Real start recents"); 148 mTaskSupervisor.startSpecificActivity(targetActivity, false /* andResume */, 149 false /* checkConfig */); 150 // Make sure the activity won't be involved in transition. 151 if (targetActivity.getDisplayContent() != null) { 152 targetActivity.getDisplayContent().mUnknownAppVisibilityController 153 .appRemovedOrHidden(targetActivity); 154 } 155 } 156 157 // Invisible activity should be stopped. If the recents activity is alive and its doesn't 158 // need to relaunch by current configuration, then it may be already in stopped state. 159 if (!targetActivity.isState(STOPPING, STOPPED)) { 160 // Add to stopping instead of stop immediately. So the client has the chance to perform 161 // traversal in non-stopped state (ViewRootImpl.mStopped) that would initialize more 162 // things (e.g. the measure can be done earlier). The actual stop will be performed when 163 // it reports idle. 164 targetActivity.addToStopping(true /* scheduleIdle */, true /* idleDelayed */, 165 "preloadRecents"); 166 } 167 } 168 startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner, long eventTime)169 void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner, long eventTime) { 170 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "startRecentsActivity(): intent=%s", mTargetIntent); 171 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "RecentsAnimation#startRecentsActivity"); 172 173 // Cancel any existing recents animation running synchronously (do not hold the 174 // WM lock) before starting the newly requested recents animation as they can not coexist 175 if (mWindowManager.getRecentsAnimationController() != null) { 176 mWindowManager.getRecentsAnimationController().forceCancelAnimation( 177 REORDER_MOVE_TO_ORIGINAL_POSITION, "startRecentsActivity"); 178 } 179 180 // If the activity is associated with the root recents task, then try and get that first 181 Task targetRootTask = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, 182 mTargetActivityType); 183 ActivityRecord targetActivity = getTargetActivity(targetRootTask); 184 final boolean hasExistingActivity = targetActivity != null; 185 if (hasExistingActivity) { 186 mRestoreTargetBehindRootTask = getRootTaskAbove(targetRootTask); 187 if (mRestoreTargetBehindRootTask == null 188 && targetRootTask.getTopMostTask() == targetActivity.getTask()) { 189 notifyAnimationCancelBeforeStart(recentsAnimationRunner); 190 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, 191 "No root task above target root task=%s", targetRootTask); 192 return; 193 } 194 } 195 196 // Send launch hint if we are actually launching the target. If it's already visible 197 // (shouldn't happen in general) we don't need to send it. 198 if (targetActivity == null || !targetActivity.isVisibleRequested()) { 199 mService.mRootWindowContainer.startPowerModeLaunchIfNeeded( 200 true /* forceSend */, targetActivity); 201 } 202 203 final LaunchingState launchingState = 204 mTaskSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent); 205 206 setProcessAnimating(true); 207 208 mService.deferWindowLayout(); 209 try { 210 if (hasExistingActivity) { 211 // Move the recents activity into place for the animation if it is not top most 212 mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(targetRootTask); 213 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved rootTask=%s behind rootTask=%s", 214 targetRootTask, getRootTaskAbove(targetRootTask)); 215 216 // If there are multiple tasks in the target root task (ie. the root home task, 217 // with 3p and default launchers coexisting), then move the task to the top as a 218 // part of moving the root task to the front 219 final Task task = targetActivity.getTask(); 220 if (targetRootTask.getTopMostTask() != task) { 221 targetRootTask.positionChildAtTop(task); 222 } 223 } else { 224 // No recents activity, create the new recents activity bottom most 225 startRecentsActivityInBackground("startRecentsActivity_noTargetActivity"); 226 227 // Move the recents activity into place for the animation 228 targetRootTask = mDefaultTaskDisplayArea.getRootTask(WINDOWING_MODE_UNDEFINED, 229 mTargetActivityType); 230 targetActivity = getTargetActivity(targetRootTask); 231 mDefaultTaskDisplayArea.moveRootTaskBehindBottomMostVisibleRootTask(targetRootTask); 232 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Moved rootTask=%s behind rootTask=%s", 233 targetRootTask, getRootTaskAbove(targetRootTask)); 234 235 mWindowManager.prepareAppTransitionNone(); 236 mWindowManager.executeAppTransition(); 237 238 // TODO: Maybe wait for app to draw in this particular case? 239 240 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "Started intent=%s", mTargetIntent); 241 } 242 243 // Mark the target activity as launch-behind to bump its visibility for the 244 // duration of the gesture that is driven by the recents component 245 targetActivity.mLaunchTaskBehind = true; 246 mLaunchedTargetActivity = targetActivity; 247 // TODO(b/156772625): Evaluate to send new intents vs. replacing the intent extras. 248 targetActivity.intent.replaceExtras(mTargetIntent); 249 250 // Fetch all the surface controls and pass them to the client to get the animation 251 // started 252 mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner, 253 this, mDefaultTaskDisplayArea.getDisplayId(), 254 mTaskSupervisor.mRecentTasks.getRecentTaskIds(), targetActivity); 255 256 // If we updated the launch-behind state, update the visibility of the activities after 257 // we fetch the visible tasks to be controlled by the animation 258 mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS); 259 260 ActivityOptions options = null; 261 if (eventTime > 0) { 262 options = ActivityOptions.makeBasic(); 263 options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime); 264 } 265 mTaskSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, 266 START_TASK_TO_FRONT, !hasExistingActivity, targetActivity, options); 267 268 // Register for root task order changes 269 mDefaultTaskDisplayArea.registerRootTaskOrderChangedListener(this); 270 } catch (Exception e) { 271 Slog.e(TAG, "Failed to start recents activity", e); 272 throw e; 273 } finally { 274 mService.continueWindowLayout(); 275 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 276 } 277 } 278 finishAnimation(@ecentsAnimationController.ReorderMode int reorderMode, boolean sendUserLeaveHint)279 private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode, 280 boolean sendUserLeaveHint) { 281 synchronized (mService.mGlobalLock) { 282 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, 283 "onAnimationFinished(): controller=%s reorderMode=%d", 284 mWindowManager.getRecentsAnimationController(), reorderMode); 285 286 // Unregister for root task order changes 287 mDefaultTaskDisplayArea.unregisterRootTaskOrderChangedListener(this); 288 289 final RecentsAnimationController controller = 290 mWindowManager.getRecentsAnimationController(); 291 if (controller == null) return; 292 293 // Just to be sure end the launch hint in case the target activity was never launched. 294 // However, if we're keeping the activity and making it visible, we can leave it on. 295 if (reorderMode != REORDER_KEEP_IN_PLACE) { 296 mService.endLaunchPowerMode( 297 ActivityTaskManagerService.POWER_MODE_REASON_START_ACTIVITY); 298 } 299 300 // Once the target is shown, prevent spurious background app switches 301 if (reorderMode == REORDER_MOVE_TO_TOP) { 302 mService.stopAppSwitches(); 303 } 304 305 mWindowManager.inSurfaceTransaction(() -> { 306 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, 307 "RecentsAnimation#onAnimationFinished_inSurfaceTransaction"); 308 mService.deferWindowLayout(); 309 try { 310 mWindowManager.cleanupRecentsAnimation(reorderMode); 311 312 final Task targetRootTask = mDefaultTaskDisplayArea.getRootTask( 313 WINDOWING_MODE_UNDEFINED, mTargetActivityType); 314 // Prefer to use the original target activity instead of top activity because 315 // we may have moved another task to top (starting 3p launcher). 316 final ActivityRecord targetActivity = targetRootTask != null 317 ? targetRootTask.isInTask(mLaunchedTargetActivity) 318 : null; 319 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, 320 "onAnimationFinished(): targetRootTask=%s targetActivity=%s " 321 + "mRestoreTargetBehindRootTask=%s", 322 targetRootTask, targetActivity, mRestoreTargetBehindRootTask); 323 if (targetActivity == null) { 324 return; 325 } 326 327 // Restore the launched-behind state 328 targetActivity.mLaunchTaskBehind = false; 329 330 if (reorderMode == REORDER_MOVE_TO_TOP) { 331 // Bring the target root task to the front 332 mTaskSupervisor.mNoAnimActivities.add(targetActivity); 333 334 if (sendUserLeaveHint) { 335 // Setting this allows the previous app to PiP. 336 mTaskSupervisor.mUserLeaving = true; 337 targetRootTask.moveTaskToFront(targetActivity.getTask(), 338 true /* noAnimation */, null /* activityOptions */, 339 targetActivity.appTimeTracker, 340 "RecentsAnimation.onAnimationFinished()"); 341 } else { 342 targetRootTask.moveToFront("RecentsAnimation.onAnimationFinished()"); 343 } 344 345 if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) { 346 final Task topRootTask = getTopNonAlwaysOnTopRootTask(); 347 if (topRootTask != targetRootTask) { 348 ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS, 349 "Expected target rootTask=%s" 350 + " to be top most but found rootTask=%s", 351 targetRootTask, topRootTask); 352 } 353 } 354 } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){ 355 // Restore the target root task to its previous position 356 final TaskDisplayArea taskDisplayArea = targetActivity.getDisplayArea(); 357 taskDisplayArea.moveRootTaskBehindRootTask(targetRootTask, 358 mRestoreTargetBehindRootTask); 359 if (WM_DEBUG_RECENTS_ANIMATIONS.isLogToAny()) { 360 final Task aboveTargetRootTask = getRootTaskAbove(targetRootTask); 361 if (mRestoreTargetBehindRootTask != null 362 && aboveTargetRootTask != mRestoreTargetBehindRootTask) { 363 ProtoLog.w(WM_DEBUG_RECENTS_ANIMATIONS, 364 "Expected target rootTask=%s to restored behind " 365 + "rootTask=%s but it is behind rootTask=%s", 366 targetRootTask, mRestoreTargetBehindRootTask, 367 aboveTargetRootTask); 368 } 369 } 370 } else { 371 // If there is no recents screenshot animation, we can update the visibility 372 // of target root task immediately because it is visually invisible and the 373 // launch-behind state is restored. That also prevents the next transition 374 // type being disturbed if the visibility is updated after setting the next 375 // transition (the target activity will be one of closing apps). 376 if (!controller.shouldDeferCancelWithScreenshot() 377 && !targetRootTask.isFocusedRootTaskOnDisplay()) { 378 targetRootTask.ensureActivitiesVisible(null /* starting */, 379 0 /* starting */, false /* preserveWindows */); 380 } 381 // Keep target root task in place, nothing changes, so ignore the transition 382 // logic below 383 return; 384 } 385 386 mWindowManager.prepareAppTransitionNone(); 387 mService.mRootWindowContainer.ensureActivitiesVisible(null, 0, false); 388 mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); 389 390 // No reason to wait for the pausing activity in this case, as the hiding of 391 // surfaces needs to be done immediately. 392 mWindowManager.executeAppTransition(); 393 394 final Task rootTask = targetRootTask.getRootTask(); 395 // Client state may have changed during the recents animation, so force 396 // send task info so the client can synchronize its state. 397 rootTask.dispatchTaskInfoChangedIfNeeded(true /* force */); 398 } catch (Exception e) { 399 Slog.e(TAG, "Failed to clean up recents activity", e); 400 throw e; 401 } finally { 402 mTaskSupervisor.mUserLeaving = false; 403 mService.continueWindowLayout(); 404 // Make sure the surfaces are updated with the latest state. Sometimes the 405 // surface placement may be skipped if display configuration is changed (i.e. 406 // {@link DisplayContent#mWaitingForConfig} is true). 407 if (mWindowManager.mRoot.isLayoutNeeded()) { 408 mWindowManager.mRoot.performSurfacePlacement(); 409 } 410 setProcessAnimating(false); 411 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 412 } 413 }); 414 } 415 } 416 417 /** Gives the owner of recents animation higher priority. */ setProcessAnimating(boolean animating)418 private void setProcessAnimating(boolean animating) { 419 if (mCaller == null) return; 420 // Apply the top-app scheduling group to who runs the animation. 421 mCaller.setRunningRecentsAnimation(animating); 422 int demoteReasons = mService.mDemoteTopAppReasons; 423 if (animating) { 424 demoteReasons |= ActivityTaskManagerService.DEMOTE_TOP_REASON_ANIMATING_RECENTS; 425 } else { 426 demoteReasons &= ~ActivityTaskManagerService.DEMOTE_TOP_REASON_ANIMATING_RECENTS; 427 } 428 mService.mDemoteTopAppReasons = demoteReasons; 429 // Make the demotion of the real top app take effect. No need to restore top app state for 430 // finishing recents because addToStopping -> scheduleIdle -> activityIdleInternal -> 431 // trimApplications will have a full update. 432 if (animating && mService.mTopApp != null) { 433 mService.mTopApp.scheduleUpdateOomAdj(); 434 } 435 } 436 437 @Override onAnimationFinished(@ecentsAnimationController.ReorderMode int reorderMode, boolean sendUserLeaveHint)438 public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode, 439 boolean sendUserLeaveHint) { 440 finishAnimation(reorderMode, sendUserLeaveHint); 441 } 442 443 @Override onRootTaskOrderChanged(Task rootTask)444 public void onRootTaskOrderChanged(Task rootTask) { 445 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "onRootTaskOrderChanged(): rootTask=%s", rootTask); 446 if (mDefaultTaskDisplayArea.getRootTask(t -> t == rootTask) == null 447 || !rootTask.shouldBeVisible(null)) { 448 // The root task is not visible, so ignore this change 449 return; 450 } 451 final RecentsAnimationController controller = 452 mWindowManager.getRecentsAnimationController(); 453 if (controller == null) { 454 return; 455 } 456 457 // We defer canceling the recents animation until the next app transition in the following 458 // cases: 459 // 1) The next launching task is not being animated by the recents animation 460 // 2) The next task is home activity. (i.e. pressing home key to back home in recents). 461 if ((!controller.isAnimatingTask(rootTask.getTopMostTask()) 462 || controller.isTargetApp(rootTask.getTopNonFinishingActivity())) 463 && controller.shouldDeferCancelUntilNextTransition()) { 464 // Always prepare an app transition since we rely on the transition callbacks to cleanup 465 mWindowManager.prepareAppTransitionNone(); 466 controller.setCancelOnNextTransitionStart(); 467 } 468 } 469 startRecentsActivityInBackground(String reason)470 private void startRecentsActivityInBackground(String reason) { 471 final ActivityOptions options = ActivityOptions.makeBasic(); 472 options.setLaunchActivityType(mTargetActivityType); 473 options.setAvoidMoveToFront(); 474 mTargetIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION); 475 476 mActivityStartController 477 .obtainStarter(mTargetIntent, reason) 478 .setCallingUid(mRecentsUid) 479 .setCallingPackage(mRecentsComponent.getPackageName()) 480 .setCallingFeatureId(mRecentsFeatureId) 481 .setActivityOptions(new SafeActivityOptions(options)) 482 .setUserId(mUserId) 483 .execute(); 484 } 485 486 /** 487 * Called only when the animation should be canceled prior to starting. 488 */ notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner)489 static void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) { 490 try { 491 recentsAnimationRunner.onAnimationCanceled(null /* taskIds */, 492 null /* taskSnapshots */); 493 } catch (RemoteException e) { 494 Slog.e(TAG, "Failed to cancel recents animation before start", e); 495 } 496 } 497 498 /** 499 * @return The top root task that is not always-on-top. 500 */ getTopNonAlwaysOnTopRootTask()501 private Task getTopNonAlwaysOnTopRootTask() { 502 return mDefaultTaskDisplayArea.getRootTask(task -> 503 !task.getWindowConfiguration().isAlwaysOnTop()); 504 } 505 506 /** 507 * @return the top activity in the {@param targetRootTask} matching the {@param component}, 508 * or just the top activity of the top task if no task matches the component. 509 */ getTargetActivity(Task targetRootTask)510 private ActivityRecord getTargetActivity(Task targetRootTask) { 511 if (targetRootTask == null) { 512 return null; 513 } 514 515 final PooledPredicate p = PooledLambda.obtainPredicate(RecentsAnimation::matchesTarget, 516 this, PooledLambda.__(Task.class)); 517 final Task task = targetRootTask.getTask(p); 518 p.recycle(); 519 return task != null ? task.getTopNonFinishingActivity() : null; 520 } 521 matchesTarget(Task task)522 private boolean matchesTarget(Task task) { 523 return task.getNonFinishingActivityCount() > 0 && task.mUserId == mUserId 524 && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent()); 525 } 526 } 527