RecentsAnimation.java revision 82389a9333718fd24ab1d7bc046b696074d65956
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 17package com.android.server.am; 18 19import static android.app.ActivityManager.START_TASK_TO_FRONT; 20import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE; 21import static android.app.AppOpsManager.OP_NONE; 22import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 23import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 24import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 25import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 26import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; 27import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; 28import static android.view.WindowManager.TRANSIT_NONE; 29import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; 30import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE; 31import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION; 32import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP; 33 34import android.app.ActivityOptions; 35import android.app.AppOpsManager; 36import android.app.IAssistDataReceiver; 37import android.content.ComponentName; 38import android.content.Context; 39import android.content.Intent; 40import android.os.RemoteException; 41import android.os.Trace; 42import android.util.Slog; 43import android.view.IRecentsAnimationRunner; 44import com.android.server.wm.RecentsAnimationController; 45import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; 46import com.android.server.wm.WindowManagerService; 47 48/** 49 * Manages the recents animation, including the reordering of the stacks for the transition and 50 * cleanup. See {@link com.android.server.wm.RecentsAnimationController}. 51 */ 52class RecentsAnimation implements RecentsAnimationCallbacks { 53 private static final String TAG = RecentsAnimation.class.getSimpleName(); 54 // TODO (b/73188263): Reset debugging flags 55 private static final boolean DEBUG = true; 56 57 private final ActivityManagerService mService; 58 private final ActivityStackSupervisor mStackSupervisor; 59 private final ActivityStartController mActivityStartController; 60 private final WindowManagerService mWindowManager; 61 private final UserController mUserController; 62 private final ActivityDisplay mDefaultDisplay; 63 private final int mCallingPid; 64 65 private int mTargetActivityType; 66 private AssistDataRequester mAssistDataRequester; 67 68 // The stack to restore the target stack behind when the animation is finished 69 private ActivityStack mRestoreTargetBehindStack; 70 71 RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor, 72 ActivityStartController activityStartController, WindowManagerService wm, 73 UserController userController, int callingPid) { 74 mService = am; 75 mStackSupervisor = stackSupervisor; 76 mDefaultDisplay = stackSupervisor.getDefaultDisplay(); 77 mActivityStartController = activityStartController; 78 mWindowManager = wm; 79 mUserController = userController; 80 mCallingPid = callingPid; 81 } 82 83 void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner, 84 ComponentName recentsComponent, int recentsUid, 85 IAssistDataReceiver assistDataReceiver) { 86 if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + intent 87 + " assistDataReceiver=" + assistDataReceiver); 88 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity"); 89 90 if (!mWindowManager.canStartRecentsAnimation()) { 91 notifyAnimationCancelBeforeStart(recentsAnimationRunner); 92 if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition=" 93 + mWindowManager.getPendingAppTransition()); 94 return; 95 } 96 97 // If the activity is associated with the recents stack, then try and get that first 98 mTargetActivityType = intent.getComponent() != null 99 && recentsComponent.equals(intent.getComponent()) 100 ? ACTIVITY_TYPE_RECENTS 101 : ACTIVITY_TYPE_HOME; 102 final ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED, 103 mTargetActivityType); 104 ActivityRecord targetActivity = getTargetActivity(targetStack, intent.getComponent()); 105 final boolean hasExistingActivity = targetActivity != null; 106 if (hasExistingActivity) { 107 final ActivityDisplay display = targetActivity.getDisplay(); 108 mRestoreTargetBehindStack = display.getStackAbove(targetStack); 109 if (mRestoreTargetBehindStack == null) { 110 notifyAnimationCancelBeforeStart(recentsAnimationRunner); 111 if (DEBUG) Slog.d(TAG, "No stack above target stack=" + targetStack); 112 return; 113 } 114 } 115 116 // Send launch hint if we are actually launching the target. If it's already visible 117 // (shouldn't happen in general) we don't need to send it. 118 if (targetActivity == null || !targetActivity.visible) { 119 mStackSupervisor.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */, 120 targetActivity); 121 } 122 123 mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(); 124 125 mService.setRunningRemoteAnimation(mCallingPid, true); 126 127 mWindowManager.deferSurfaceLayout(); 128 try { 129 // Kick off the assist data request in the background before showing the target activity 130 if (assistDataReceiver != null) { 131 final AppOpsManager appOpsManager = (AppOpsManager) 132 mService.mContext.getSystemService(Context.APP_OPS_SERVICE); 133 final AssistDataReceiverProxy proxy = new AssistDataReceiverProxy( 134 assistDataReceiver, recentsComponent.getPackageName()); 135 mAssistDataRequester = new AssistDataRequester(mService.mContext, mService, 136 mWindowManager, appOpsManager, proxy, this, OP_ASSIST_STRUCTURE, OP_NONE); 137 mAssistDataRequester.requestAssistData(mStackSupervisor.getTopVisibleActivities(), 138 true /* fetchData */, false /* fetchScreenshots */, 139 true /* allowFetchData */, false /* allowFetchScreenshots */, 140 recentsUid, recentsComponent.getPackageName()); 141 } 142 143 final ActivityDisplay display; 144 if (hasExistingActivity) { 145 // Move the recents activity into place for the animation if it is not top most 146 display = targetActivity.getDisplay(); 147 display.moveStackBehindBottomMostVisibleStack(targetStack); 148 if (DEBUG) Slog.d(TAG, "Moved stack=" + targetStack + " behind stack=" 149 + display.getStackAbove(targetStack)); 150 151 // If there are multiple tasks in the target stack (ie. the home stack, with 3p 152 // and default launchers coexisting), then move the task to the top as a part of 153 // moving the stack to the front 154 if (targetStack.topTask() != targetActivity.getTask()) { 155 targetStack.addTask(targetActivity.getTask(), true /* toTop */, 156 "startRecentsActivity"); 157 } 158 } else { 159 // No recents activity 160 ActivityOptions options = ActivityOptions.makeBasic(); 161 options.setLaunchActivityType(mTargetActivityType); 162 options.setAvoidMoveToFront(); 163 intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION); 164 165 mActivityStartController 166 .obtainStarter(intent, "startRecentsActivity_noTargetActivity") 167 .setCallingUid(recentsUid) 168 .setCallingPackage(recentsComponent.getPackageName()) 169 .setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle())) 170 .setMayWait(mUserController.getCurrentUserId()) 171 .execute(); 172 mWindowManager.prepareAppTransition(TRANSIT_NONE, false); 173 174 targetActivity = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED, 175 mTargetActivityType).getTopActivity(); 176 display = targetActivity.getDisplay(); 177 178 // TODO: Maybe wait for app to draw in this particular case? 179 180 if (DEBUG) Slog.d(TAG, "Started intent=" + intent); 181 } 182 183 // Mark the target activity as launch-behind to bump its visibility for the 184 // duration of the gesture that is driven by the recents component 185 targetActivity.mLaunchTaskBehind = true; 186 187 // Fetch all the surface controls and pass them to the client to get the animation 188 // started. Cancel any existing recents animation running synchronously (do not hold the 189 // WM lock) 190 mWindowManager.cancelRecentsAnimationSynchronously(REORDER_MOVE_TO_ORIGINAL_POSITION, 191 "startRecentsActivity"); 192 mWindowManager.initializeRecentsAnimation(mTargetActivityType, recentsAnimationRunner, 193 this, display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds()); 194 195 // If we updated the launch-behind state, update the visibility of the activities after 196 // we fetch the visible tasks to be controlled by the animation 197 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); 198 199 mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT, 200 targetActivity); 201 } catch (Exception e) { 202 Slog.e(TAG, "Failed to start recents activity", e); 203 throw e; 204 } finally { 205 mWindowManager.continueSurfaceLayout(); 206 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 207 } 208 } 209 210 private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) { 211 synchronized (mService) { 212 if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller=" 213 + mWindowManager.getRecentsAnimationController() 214 + " reorderMode=" + reorderMode); 215 216 // Cancel the associated assistant data request 217 if (mAssistDataRequester != null) { 218 mAssistDataRequester.cancel(); 219 mAssistDataRequester = null; 220 } 221 222 if (mWindowManager.getRecentsAnimationController() == null) return; 223 224 // Just to be sure end the launch hint in case the target activity was never launched. 225 // However, if we're keeping the activity and making it visible, we can leave it on. 226 if (reorderMode != REORDER_KEEP_IN_PLACE) { 227 mStackSupervisor.sendPowerHintForLaunchEndIfNeeded(); 228 } 229 230 mService.setRunningRemoteAnimation(mCallingPid, false); 231 232 mWindowManager.inSurfaceTransaction(() -> { 233 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, 234 "RecentsAnimation#onAnimationFinished_inSurfaceTransaction"); 235 mWindowManager.deferSurfaceLayout(); 236 try { 237 mWindowManager.cleanupRecentsAnimation(reorderMode); 238 239 final ActivityStack targetStack = mDefaultDisplay.getStack( 240 WINDOWING_MODE_UNDEFINED, mTargetActivityType); 241 final ActivityRecord targetActivity = targetStack != null 242 ? targetStack.getTopActivity() 243 : null; 244 if (DEBUG) Slog.d(TAG, "onAnimationFinished(): targetStack=" + targetStack 245 + " targetActivity=" + targetActivity 246 + " mRestoreTargetBehindStack=" + mRestoreTargetBehindStack); 247 if (targetActivity == null) { 248 return; 249 } 250 251 // Restore the launched-behind state 252 targetActivity.mLaunchTaskBehind = false; 253 254 if (reorderMode == REORDER_MOVE_TO_TOP) { 255 // Bring the target stack to the front 256 mStackSupervisor.mNoAnimActivities.add(targetActivity); 257 targetStack.moveToFront("RecentsAnimation.onAnimationFinished()"); 258 if (DEBUG) { 259 final ActivityStack topStack = getTopNonAlwaysOnTopStack(); 260 if (topStack != targetStack) { 261 Slog.w(TAG, "Expected target stack=" + targetStack 262 + " to be top most but found stack=" + topStack); 263 } 264 } 265 } else if (reorderMode == REORDER_MOVE_TO_ORIGINAL_POSITION){ 266 // Restore the target stack to its previous position 267 final ActivityDisplay display = targetActivity.getDisplay(); 268 display.moveStackBehindStack(targetStack, mRestoreTargetBehindStack); 269 if (DEBUG) { 270 final ActivityStack aboveTargetStack = 271 mDefaultDisplay.getStackAbove(targetStack); 272 if (mRestoreTargetBehindStack != null 273 && aboveTargetStack != mRestoreTargetBehindStack) { 274 Slog.w(TAG, "Expected target stack=" + targetStack 275 + " to restored behind stack=" + mRestoreTargetBehindStack 276 + " but it is behind stack=" + aboveTargetStack); 277 } 278 } 279 } else { 280 // Keep target stack in place, nothing changes, so ignore the transition 281 // logic below 282 return; 283 } 284 285 mWindowManager.prepareAppTransition(TRANSIT_NONE, false); 286 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, false); 287 mStackSupervisor.resumeFocusedStackTopActivityLocked(); 288 289 // No reason to wait for the pausing activity in this case, as the hiding of 290 // surfaces needs to be done immediately. 291 mWindowManager.executeAppTransition(); 292 293 // After reordering the stacks, reset the minimized state. At this point, either 294 // the target activity is now top-most and we will stay minimized (if in 295 // split-screen), or we will have returned to the app, and the minimized state 296 // should be reset 297 mWindowManager.checkSplitScreenMinimizedChanged(true /* animate */); 298 } catch (Exception e) { 299 Slog.e(TAG, "Failed to clean up recents activity", e); 300 throw e; 301 } finally { 302 mWindowManager.continueSurfaceLayout(); 303 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 304 } 305 }); 306 } 307 } 308 309 @Override 310 public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode, 311 boolean runSychronously) { 312 if (runSychronously) { 313 finishAnimation(reorderMode); 314 } else { 315 mService.mHandler.post(() -> finishAnimation(reorderMode)); 316 } 317 } 318 319 /** 320 * Called only when the animation should be canceled prior to starting. 321 */ 322 private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) { 323 try { 324 recentsAnimationRunner.onAnimationCanceled(); 325 } catch (RemoteException e) { 326 Slog.e(TAG, "Failed to cancel recents animation before start", e); 327 } 328 } 329 330 /** 331 * @return The top stack that is not always-on-top. 332 */ 333 private ActivityStack getTopNonAlwaysOnTopStack() { 334 for (int i = mDefaultDisplay.getChildCount() - 1; i >= 0; i--) { 335 final ActivityStack s = mDefaultDisplay.getChildAt(i); 336 if (s.getWindowConfiguration().isAlwaysOnTop()) { 337 continue; 338 } 339 return s; 340 } 341 return null; 342 } 343 344 /** 345 * @return the top activity in the {@param targetStack} matching the {@param component}, or just 346 * the top activity of the top task if no task matches the component. 347 */ 348 private ActivityRecord getTargetActivity(ActivityStack targetStack, ComponentName component) { 349 if (targetStack == null) { 350 return null; 351 } 352 353 for (int i = targetStack.getChildCount() - 1; i >= 0; i--) { 354 final TaskRecord task = (TaskRecord) targetStack.getChildAt(i); 355 if (task.getBaseIntent().getComponent().equals(component)) { 356 return task.getTopActivity(); 357 } 358 } 359 return targetStack.getTopActivity(); 360 } 361} 362