RecentsAnimation.java revision 54cff64ec6ef818e270eb39a74d6a58068553d66
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.WindowConfiguration.ACTIVITY_TYPE_HOME; 21import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 22import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION; 23import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; 24import static android.view.WindowManager.TRANSIT_NONE; 25import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS; 26 27import android.app.ActivityOptions; 28import android.content.ComponentName; 29import android.content.Intent; 30import android.os.Handler; 31import android.os.RemoteException; 32import android.os.Trace; 33import android.util.Slog; 34import android.view.IRecentsAnimationRunner; 35import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks; 36import com.android.server.wm.WindowManagerService; 37 38/** 39 * Manages the recents animation, including the reordering of the stacks for the transition and 40 * cleanup. See {@link com.android.server.wm.RecentsAnimationController}. 41 */ 42class RecentsAnimation implements RecentsAnimationCallbacks { 43 private static final String TAG = RecentsAnimation.class.getSimpleName(); 44 45 private static final int RECENTS_ANIMATION_TIMEOUT = 10 * 1000; 46 47 private final ActivityManagerService mService; 48 private final ActivityStackSupervisor mStackSupervisor; 49 private final ActivityStartController mActivityStartController; 50 private final WindowManagerService mWindowManager; 51 private final UserController mUserController; 52 private final Handler mHandler; 53 private final int mCallingPid; 54 55 private final Runnable mCancelAnimationRunnable; 56 57 // The stack to restore the home stack behind when the animation is finished 58 private ActivityStack mRestoreHomeBehindStack; 59 60 RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor, 61 ActivityStartController activityStartController, WindowManagerService wm, 62 UserController userController, int callingPid) { 63 mService = am; 64 mStackSupervisor = stackSupervisor; 65 mActivityStartController = activityStartController; 66 mHandler = new Handler(mStackSupervisor.mLooper); 67 mWindowManager = wm; 68 mUserController = userController; 69 mCallingPid = callingPid; 70 71 mCancelAnimationRunnable = () -> { 72 // The caller has not finished the animation in a predefined amount of time, so 73 // force-cancel the animation 74 mWindowManager.cancelRecentsAnimation(); 75 }; 76 } 77 78 void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner, 79 ComponentName recentsComponent, int recentsUid) { 80 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity"); 81 82 if (!mWindowManager.canStartRecentsAnimation()) { 83 notifyAnimationCancelBeforeStart(recentsAnimationRunner); 84 return; 85 } 86 87 // If the existing home activity is already on top, then cancel 88 ActivityRecord homeActivity = mStackSupervisor.getHomeActivity(); 89 final boolean hasExistingHomeActivity = homeActivity != null; 90 if (hasExistingHomeActivity) { 91 final ActivityDisplay display = homeActivity.getDisplay(); 92 mRestoreHomeBehindStack = display.getStackAboveHome(); 93 if (mRestoreHomeBehindStack == null) { 94 notifyAnimationCancelBeforeStart(recentsAnimationRunner); 95 return; 96 } 97 } 98 99 mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(); 100 101 mService.setRunningRemoteAnimation(mCallingPid, true); 102 103 mWindowManager.deferSurfaceLayout(); 104 try { 105 final ActivityDisplay display; 106 if (hasExistingHomeActivity) { 107 // Move the home activity into place for the animation if it is not already top most 108 display = homeActivity.getDisplay(); 109 display.moveHomeStackBehindBottomMostVisibleStack(); 110 } else { 111 // No home activity 112 final ActivityOptions opts = ActivityOptions.makeBasic(); 113 opts.setLaunchActivityType(ACTIVITY_TYPE_HOME); 114 opts.setAvoidMoveToFront(); 115 intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION); 116 117 mActivityStartController 118 .obtainStarter(intent, "startRecentsActivity_noHomeActivity") 119 .setCallingUid(recentsUid) 120 .setCallingPackage(recentsComponent.getPackageName()) 121 .setActivityOptions(SafeActivityOptions.fromBundle(opts.toBundle())) 122 .setMayWait(mUserController.getCurrentUserId()) 123 .execute(); 124 mWindowManager.prepareAppTransition(TRANSIT_NONE, false); 125 126 homeActivity = mStackSupervisor.getHomeActivity(); 127 display = homeActivity.getDisplay(); 128 129 // TODO: Maybe wait for app to draw in this particular case? 130 } 131 132 // Mark the home activity as launch-behind to bump its visibility for the 133 // duration of the gesture that is driven by the recents component 134 homeActivity.mLaunchTaskBehind = true; 135 136 // Post a timeout for the animation. This needs to happen before initializing the 137 // recents animation on the WM side since we may decide to cancel the animation there 138 mHandler.postDelayed(mCancelAnimationRunnable, RECENTS_ANIMATION_TIMEOUT); 139 140 // Fetch all the surface controls and pass them to the client to get the animation 141 // started 142 mWindowManager.cancelRecentsAnimation(); 143 mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this, 144 display.mDisplayId, mStackSupervisor.mRecentTasks.getRecentTaskIds()); 145 146 // If we updated the launch-behind state, update the visibility of the activities after 147 // we fetch the visible tasks to be controlled by the animation 148 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS); 149 150 mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT, 151 homeActivity); 152 } finally { 153 mWindowManager.continueSurfaceLayout(); 154 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 155 } 156 } 157 158 @Override 159 public void onAnimationFinished(boolean moveHomeToTop) { 160 mHandler.removeCallbacks(mCancelAnimationRunnable); 161 synchronized (mService) { 162 if (mWindowManager.getRecentsAnimationController() == null) return; 163 164 mService.setRunningRemoteAnimation(mCallingPid, false); 165 166 mWindowManager.inSurfaceTransaction(() -> { 167 Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, 168 "RecentsAnimation#onAnimationFinished_inSurfaceTransaction"); 169 mWindowManager.deferSurfaceLayout(); 170 try { 171 mWindowManager.cleanupRecentsAnimation(); 172 173 // Move the home stack to the front 174 final ActivityRecord homeActivity = mStackSupervisor.getHomeActivity(); 175 if (homeActivity == null) { 176 return; 177 } 178 179 // Restore the launched-behind state 180 homeActivity.mLaunchTaskBehind = false; 181 182 if (moveHomeToTop) { 183 // Bring the home stack to the front 184 final ActivityStack homeStack = homeActivity.getStack(); 185 mStackSupervisor.mNoAnimActivities.add(homeActivity); 186 homeStack.moveToFront("RecentsAnimation.onAnimationFinished()"); 187 } else { 188 // Restore the home stack to its previous position 189 final ActivityDisplay display = homeActivity.getDisplay(); 190 display.moveHomeStackBehindStack(mRestoreHomeBehindStack); 191 } 192 193 mWindowManager.prepareAppTransition(TRANSIT_NONE, false); 194 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, false); 195 mStackSupervisor.resumeFocusedStackTopActivityLocked(); 196 197 // No reason to wait for the pausing activity in this case, as the hiding of 198 // surfaces needs to be done immediately. 199 mWindowManager.executeAppTransition(); 200 } finally { 201 mWindowManager.continueSurfaceLayout(); 202 Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); 203 } 204 }); 205 } 206 } 207 208 /** 209 * Called only when the animation should be canceled prior to starting. 210 */ 211 private void notifyAnimationCancelBeforeStart(IRecentsAnimationRunner recentsAnimationRunner) { 212 try { 213 recentsAnimationRunner.onAnimationCanceled(); 214 } catch (RemoteException e) { 215 Slog.e(TAG, "Failed to cancel recents animation before start", e); 216 } 217 } 218} 219