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