blob: 1575694dc825d283a31d85fb2c7a89d3b6ba564c [file] [log] [blame]
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -08001/*
2 * Copyright (C) 2016 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.wm;
18
19import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
20import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
Matthew Ng606dd802017-06-05 14:06:32 -070021
Jorim Jaggif84e2f62018-01-16 14:17:59 +010022import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
23import static android.view.WindowManager.TRANSIT_UNSET;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080024import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080027import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
29import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
30import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080031
Jorim Jaggie2c77f92016-12-29 14:57:22 +010032import android.app.ActivityManager.TaskSnapshot;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080033import android.content.res.CompatibilityInfo;
34import android.content.res.Configuration;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080035import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080036import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080037import android.os.IBinder;
Sudheer Shankac766db02017-06-12 10:37:29 -070038import android.os.Looper;
39import android.os.Message;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080040import android.util.Slog;
41import android.view.IApplicationToken;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010042import android.view.RemoteAnimationDefinition;
43import android.view.WindowManager;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080044
Winson Chung30480042017-01-26 10:55:34 -080045import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080046import com.android.server.AttributeCache;
Adrian Roose99bc052017-11-20 17:55:31 +010047import com.android.server.policy.WindowManagerPolicy.StartingSurface;
48
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080049/**
50 * Controller for the app window token container. This is created by activity manager to link
51 * activity records to the app window token container they use in window manager.
52 *
53 * Test class: {@link AppWindowContainerControllerTests}
54 */
55public class AppWindowContainerController
56 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
57
Jorim Jaggi02886a82016-12-06 09:10:06 -080058 private static final int STARTING_WINDOW_TYPE_NONE = 0;
59 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
60 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
61
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080062 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010063 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080064
Sudheer Shankac766db02017-06-12 10:37:29 -070065 private final class H extends Handler {
66 public static final int NOTIFY_WINDOWS_DRAWN = 1;
67 public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080068
Sudheer Shankac766db02017-06-12 10:37:29 -070069 public H(Looper looper) {
70 super(looper);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080071 }
Sudheer Shankac766db02017-06-12 10:37:29 -070072
73 @Override
74 public void handleMessage(Message msg) {
75 switch (msg.what) {
76 case NOTIFY_WINDOWS_DRAWN:
77 if (mListener == null) {
78 return;
79 }
80 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
81 + AppWindowContainerController.this.mToken);
82 mListener.onWindowsDrawn(msg.getWhen());
83 break;
84 case NOTIFY_STARTING_WINDOW_DRAWN:
85 if (mListener == null) {
86 return;
87 }
88 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
89 + AppWindowContainerController.this.mToken);
90 mListener.onStartingWindowDrawn(msg.getWhen());
91 break;
92 default:
93 break;
94 }
95 }
96 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080097
98 private final Runnable mOnWindowsVisible = () -> {
99 if (mListener == null) {
100 return;
101 }
102 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
103 + AppWindowContainerController.this.mToken);
104 mListener.onWindowsVisible();
105 };
106
107 private final Runnable mOnWindowsGone = () -> {
108 if (mListener == null) {
109 return;
110 }
111 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
112 + AppWindowContainerController.this.mToken);
113 mListener.onWindowsGone();
114 };
115
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800116 private final Runnable mAddStartingWindow = () -> {
117 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100118 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800119
120 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100121 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200122 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
123 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100124 return;
125 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800126 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100127 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800128 }
129
130 if (startingData == null) {
131 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200132 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
133 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800134 return;
135 }
136
137 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100138 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800139
Jorim Jaggi02886a82016-12-06 09:10:06 -0800140 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800141 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100142 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800143 } catch (Exception e) {
144 Slog.w(TAG_WM, "Exception when adding starting window", e);
145 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800146 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800147 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800148 synchronized(mWindowMap) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200149 // If the window was successfully added, then
150 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100151 if (container.removed || container.startingData == null) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200152 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
153 "Aborted starting " + container
154 + ": removed=" + container.removed
155 + " startingData=" + container.startingData);
156 container.startingWindow = null;
157 container.startingData = null;
158 abort = true;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800159 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100160 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800161 }
162 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
163 "Added starting " + mContainer
164 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100165 + container.startingWindow + " startingView="
166 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800167 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800168 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100169 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800170 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200171 } else if (DEBUG_STARTING_WINDOW) {
172 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800173 }
174 };
175
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800176 public AppWindowContainerController(TaskWindowContainerController taskController,
177 IApplicationToken token, AppWindowContainerListener listener, int index,
178 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800179 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Bryce Leef3c6a472017-11-14 14:53:06 -0800180 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800181 this(taskController, token, listener, index, requestedOrientation, fullscreen,
182 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800183 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
184 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Bryce Leef3c6a472017-11-14 14:53:06 -0800185 WindowManagerService.getInstance());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800186 }
187
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800188 public AppWindowContainerController(TaskWindowContainerController taskController,
189 IApplicationToken token, AppWindowContainerListener listener, int index,
190 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800191 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
192 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Bryce Leef3c6a472017-11-14 14:53:06 -0800193 WindowManagerService service) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800194 super(listener, service);
Sudheer Shankac766db02017-06-12 10:37:29 -0700195 mHandler = new H(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800196 mToken = token;
197 synchronized(mWindowMap) {
198 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
199 if (atoken != null) {
200 // TODO: Should this throw an exception instead?
201 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
202 return;
203 }
204
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800205 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800206 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800207 throw new IllegalArgumentException("AppWindowContainerController: invalid "
208 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800209 }
210
Winson Chung30480042017-01-26 10:55:34 -0800211 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800212 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
213 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Bryce Leef3c6a472017-11-14 14:53:06 -0800214 alwaysFocusable, this);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800215 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800216 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800217 task.addChild(atoken, index);
218 }
219 }
220
Winson Chung30480042017-01-26 10:55:34 -0800221 @VisibleForTesting
222 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
223 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
224 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
225 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Bryce Leef3c6a472017-11-14 14:53:06 -0800226 boolean alwaysFocusable, AppWindowContainerController controller) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100227 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800228 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
229 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Bryce Leef3c6a472017-11-14 14:53:06 -0800230 controller);
Winson Chung30480042017-01-26 10:55:34 -0800231 }
232
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800233 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800234 synchronized(mWindowMap) {
235 final DisplayContent dc = mRoot.getDisplayContent(displayId);
236 if (dc == null) {
237 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
238 + mToken + " from non-existing displayId=" + displayId);
239 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800240 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800241 dc.removeAppToken(mToken.asBinder());
242 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800243 }
244 }
245
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800246 @Override
247 public void removeContainer() {
248 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800249 }
250
Winson Chung30480042017-01-26 10:55:34 -0800251 public void reparent(TaskWindowContainerController taskController, int position) {
252 synchronized (mWindowMap) {
253 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
254 + " to task=" + taskController + " at " + position);
255 if (mContainer == null) {
256 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
257 "reparent: could not find app token=" + mToken);
258 return;
259 }
260 final Task task = taskController.mContainer;
261 if (task == null) {
262 throw new IllegalArgumentException("reparent: could not find task="
263 + taskController);
264 }
265 mContainer.reparent(task, position);
266 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
267 }
268 }
269
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800270 public Configuration setOrientation(int requestedOrientation, int displayId,
271 Configuration displayConfig, boolean freezeScreenIfNeeded) {
272 synchronized(mWindowMap) {
273 if (mContainer == null) {
274 Slog.w(TAG_WM,
275 "Attempted to set orientation of non-existing app token: " + mToken);
276 return null;
277 }
278
279 mContainer.setOrientation(requestedOrientation);
280
281 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
282 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
283
284 }
285 }
286
287 public int getOrientation() {
288 synchronized(mWindowMap) {
289 if (mContainer == null) {
290 return SCREEN_ORIENTATION_UNSPECIFIED;
291 }
292
293 return mContainer.getOrientationIgnoreVisibility();
294 }
295 }
296
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100297 public void setDisablePreviewScreenshots(boolean disable) {
298 synchronized (mWindowMap) {
299 if (mContainer == null) {
300 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
301 + " token: " + mToken);
302 return;
303 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200304 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100305 }
306 }
307
Tim Murray68ed8442017-08-29 23:21:27 +0000308 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800309 synchronized(mWindowMap) {
310 if (mContainer == null) {
311 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
312 + mToken);
313 return;
314 }
315
316 final AppWindowToken wtoken = mContainer;
317
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700318 // Don't set visibility to false if we were already not visible. This prevents WM from
319 // adding the app to the closing app list which doesn't make sense for something that is
320 // already not visible. However, set visibility to true even if we are already visible.
321 // This makes sure the app is added to the opening apps list so that the right
322 // transition can be selected.
323 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
324 // concept of setting visibility...
325 if (!visible && wtoken.hiddenRequested) {
326
327 if (!deferHidingClient && wtoken.mDeferHidingClient) {
328 // We previously deferred telling the client to hide itself when visibility was
329 // initially set to false. Now we would like it to hide, so go ahead and set it.
330 wtoken.mDeferHidingClient = deferHidingClient;
331 wtoken.setClientHidden(true);
332 }
333 return;
334 }
335
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800336 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
337 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200338 + " hidden=" + wtoken.isHidden() + " hiddenRequested="
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800339 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
340
341 mService.mOpeningApps.remove(wtoken);
342 mService.mClosingApps.remove(wtoken);
343 wtoken.waitingToShow = false;
344 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700345 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800346
347 if (!visible) {
348 // If the app is dead while it was visible, we kept its dead window on screen.
349 // Now that the app is going invisible, we can remove it. It will be restarted
350 // if made visible again.
351 wtoken.removeDeadWindows();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800352 } else {
353 if (!mService.mAppTransition.isTransitionSet()
354 && mService.mAppTransition.isReady()) {
355 // Add the app mOpeningApps if transition is unset but ready. This means
356 // we're doing a screen freeze, and the unfreeze will wait for all opening
357 // apps to be ready.
358 mService.mOpeningApps.add(wtoken);
359 }
360 wtoken.startingMoved = false;
361 // If the token is currently hidden (should be the common case), or has been
362 // stopped, then we need to set up to wait for its windows to be ready.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200363 if (wtoken.isHidden() || wtoken.mAppStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800364 wtoken.clearAllDrawn();
365
366 // If the app was already visible, don't reset the waitingToShow state.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200367 if (wtoken.isHidden()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800368 wtoken.waitingToShow = true;
369 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800370 }
Jorim Jaggi067b5bf2018-02-23 17:42:39 +0100371
372 // In the case where we are making an app visible but holding off for a transition,
373 // we still need to tell the client to make its windows visible so they get drawn.
374 // Otherwise, we will wait on performing the transition until all windows have been
375 // drawn, they never will be, and we are sad.
376 wtoken.setClientHidden(false);
377
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800378 wtoken.requestUpdateWallpaperIfNeeded();
379
380 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
381 wtoken.mAppStopped = false;
Jorim Jaggi60f9c972018-02-01 19:21:07 +0100382
383 mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800384 }
385
386 // If we are preparing an app transition, then delay changing
387 // the visibility of this token until we execute that transition.
David Stevensf62360c2017-03-16 19:00:20 -0700388 if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800389 wtoken.inPendingTransaction = true;
390 if (visible) {
391 mService.mOpeningApps.add(wtoken);
392 wtoken.mEnteringAnimation = true;
393 } else {
394 mService.mClosingApps.add(wtoken);
395 wtoken.mEnteringAnimation = false;
396 }
397 if (mService.mAppTransition.getAppTransition()
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100398 == WindowManager.TRANSIT_TASK_OPEN_BEHIND) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800399 // We're launchingBehind, add the launching activity to mOpeningApps.
400 final WindowState win =
401 mService.getDefaultDisplayContentLocked().findFocusedWindow();
402 if (win != null) {
403 final AppWindowToken focusedToken = win.mAppToken;
404 if (focusedToken != null) {
405 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
406 + " adding " + focusedToken + " to mOpeningApps");
407 // Force animation to be loaded.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200408 focusedToken.setHidden(true);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800409 mService.mOpeningApps.add(focusedToken);
410 }
411 }
412 }
413 return;
414 }
415
416 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
417 wtoken.updateReportedVisibilityLocked();
418 }
419 }
420
421 /**
422 * Notifies that we launched an app that might be visible or not visible depending on what kind
423 * of Keyguard flags it's going to set on its windows.
424 */
425 public void notifyUnknownVisibilityLaunched() {
426 synchronized(mWindowMap) {
427 if (mContainer != null) {
428 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
429 }
430 }
431 }
432
433 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
434 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700435 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700436 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800437 synchronized(mWindowMap) {
438 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200439 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
440 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
441 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800442
443 if (mContainer == null) {
444 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
445 return false;
446 }
447
448 // If the display is frozen, we won't do anything until the actual window is
449 // displayed so there is no reason to put in the starting window.
David Stevensf62360c2017-03-16 19:00:20 -0700450 if (!mContainer.okToDisplay()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800451 return false;
452 }
453
454 if (mContainer.startingData != null) {
455 return false;
456 }
457
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700458 final WindowState mainWin = mContainer.findMainWindow();
Jorim Jaggie6b1b3b2017-07-24 16:44:18 +0200459 if (mainWin != null && mainWin.mWinAnimator.getShown()) {
460 // App already has a visible window...why would you want a starting window?
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700461 return false;
462 }
463
Jorim Jaggi42befc62017-06-13 11:54:04 -0700464 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
465 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
466 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggibae01b12017-04-11 16:29:10 -0700467 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700468 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800469
470 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700471 return createSnapshot(snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800472 }
473
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800474 // If this is a translucent window, then don't show a starting window -- the current
475 // effect (a full-screen opaque starting window that fades away to the real contents
476 // when it is ready) does not work for this.
477 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
478 + Integer.toHexString(theme));
479 if (theme != 0) {
480 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
481 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
482 if (ent == null) {
483 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
484 // see that.
485 return false;
486 }
487 final boolean windowIsTranslucent = ent.array.getBoolean(
488 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
489 final boolean windowIsFloating = ent.array.getBoolean(
490 com.android.internal.R.styleable.Window_windowIsFloating, false);
491 final boolean windowShowWallpaper = ent.array.getBoolean(
492 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
493 final boolean windowDisableStarting = ent.array.getBoolean(
494 com.android.internal.R.styleable.Window_windowDisablePreview, false);
495 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
496 + " Floating=" + windowIsFloating
497 + " ShowWallpaper=" + windowShowWallpaper);
498 if (windowIsTranslucent) {
499 return false;
500 }
501 if (windowIsFloating || windowDisableStarting) {
502 return false;
503 }
504 if (windowShowWallpaper) {
505 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
506 == null) {
507 // If this theme is requesting a wallpaper, and the wallpaper
508 // is not currently visible, then this effectively serves as
509 // an opaque window and our starting window transition animation
510 // can still work. We just need to make sure the starting window
511 // is also showing the wallpaper.
512 windowFlags |= FLAG_SHOW_WALLPAPER;
513 } else {
514 return false;
515 }
516 }
517 }
518
519 if (mContainer.transferStartingWindow(transferFrom)) {
520 return true;
521 }
522
Jorim Jaggi02886a82016-12-06 09:10:06 -0800523 // There is no existing starting window, and we don't want to create a splash screen, so
524 // that's it!
525 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800526 return false;
527 }
528
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200529 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100530 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800531 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
532 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800533 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800534 }
535 return true;
536 }
537
Jorim Jaggibae01b12017-04-11 16:29:10 -0700538 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700539 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
540 TaskSnapshot snapshot) {
Matthew Ng606dd802017-06-05 14:06:32 -0700541 if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
542 // TODO(b/34099271): Remove this statement to add back the starting window and figure
543 // out why it causes flickering, the starting window appears over the thumbnail while
544 // the docked from recents transition occurs
545 return STARTING_WINDOW_TYPE_NONE;
546 } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800547 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700548 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700549 return snapshot == null ? STARTING_WINDOW_TYPE_NONE
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400550 : snapshotOrientationSameAsTask(snapshot) || fromRecents
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700551 ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800552 } else {
553 return STARTING_WINDOW_TYPE_NONE;
554 }
555 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800556
Jorim Jaggi02886a82016-12-06 09:10:06 -0800557 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800558 // Note: we really want to do sendMessageAtFrontOfQueue() because we
559 // want to process the message ASAP, before any other queued
560 // messages.
561 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100562 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800563 }
564
Jorim Jaggi42befc62017-06-13 11:54:04 -0700565 private boolean createSnapshot(TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800566 if (snapshot == null) {
567 return false;
568 }
569
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200570 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200571 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800572 scheduleAddStartingWindow();
573 return true;
574 }
575
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400576 private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700577 if (snapshot == null) {
578 return false;
579 }
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400580 return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
Jorim Jaggi42befc62017-06-13 11:54:04 -0700581 }
582
Jorim Jaggi19be6052017-08-03 18:33:43 +0200583 public void removeStartingWindow() {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800584 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800585 if (mContainer.startingWindow == null) {
586 if (mContainer.startingData != null) {
587 // Starting window has not been added yet, but it is scheduled to be added.
588 // Go ahead and cancel the request.
589 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
590 "Clearing startingData for token=" + mContainer);
591 mContainer.startingData = null;
592 }
593 return;
594 }
595
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700596 final StartingSurface surface;
597 if (mContainer.startingData != null) {
598 surface = mContainer.startingSurface;
599 mContainer.startingData = null;
600 mContainer.startingSurface = null;
601 mContainer.startingWindow = null;
602 mContainer.startingDisplayed = false;
Seigo Nonakaeafe7372017-08-16 12:39:49 -0700603 if (surface == null) {
604 if (DEBUG_STARTING_WINDOW) {
605 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
606 + "remove");
607 }
608 return;
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700609 }
610 } else {
611 if (DEBUG_STARTING_WINDOW) {
612 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
613 + mContainer);
614 }
615 return;
616 }
617
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200618 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700619 + " startingWindow=" + mContainer.startingWindow
Jorim Jaggi77d0f36c2018-03-16 17:49:49 +0100620 + " startingView=" + mContainer.startingSurface
621 + " Callers=" + Debug.getCallers(5));
Jorim Jaggia3382192017-07-18 14:33:21 +0200622
623 // Use the same thread to remove the window as we used to add it, as otherwise we end up
624 // with things in the view hierarchy being called from different threads.
Jorim Jaggi8829cf12017-09-05 12:28:52 +0200625 mService.mAnimationHandler.post(() -> {
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700626 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
627 try {
628 surface.remove();
629 } catch (Exception e) {
630 Slog.w(TAG_WM, "Exception when removing starting window", e);
631 }
632 });
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800633 }
634 }
635
636 public void pauseKeyDispatching() {
637 synchronized (mWindowMap) {
638 if (mContainer != null) {
639 mService.mInputMonitor.pauseDispatchingLw(mContainer);
640 }
641 }
642 }
643
644 public void resumeKeyDispatching() {
645 synchronized (mWindowMap) {
646 if (mContainer != null) {
647 mService.mInputMonitor.resumeDispatchingLw(mContainer);
648 }
649 }
650 }
651
Jorim Jaggibae01b12017-04-11 16:29:10 -0700652 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800653 synchronized(mWindowMap) {
654 if (mContainer == null) {
655 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
656 return;
657 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700658 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800659 }
660 }
661
662 public void notifyAppStopped() {
663 synchronized(mWindowMap) {
664 if (mContainer == null) {
665 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
666 + mToken);
667 return;
668 }
669 mContainer.notifyAppStopped();
670 }
671 }
672
673 public void startFreezingScreen(int configChanges) {
674 synchronized(mWindowMap) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800675 if (mContainer == null) {
676 Slog.w(TAG_WM,
677 "Attempted to freeze screen with non-existing app token: " + mContainer);
678 return;
679 }
David Stevensf62360c2017-03-16 19:00:20 -0700680
681 if (configChanges == 0 && mContainer.okToDisplay()) {
682 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
683 return;
684 }
685
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800686 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800687 }
688 }
689
690 public void stopFreezingScreen(boolean force) {
691 synchronized(mWindowMap) {
692 if (mContainer == null) {
693 return;
694 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800695 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
Jorim Jaggib0fc8172017-11-23 17:04:08 +0000696 + mContainer.isHidden() + " freezing=" + mContainer.isFreezingScreen());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800697 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800698 }
699 }
700
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100701 public void registerRemoteAnimations(RemoteAnimationDefinition definition) {
702 synchronized (mWindowMap) {
703 if (mContainer == null) {
704 Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app"
705 + " token: " + mToken);
706 return;
707 }
708 mContainer.registerRemoteAnimations(definition);
709 }
710 }
711
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800712 void reportStartingWindowDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700713 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800714 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800715
716 void reportWindowsDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700717 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800718 }
719
720 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800721 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800722 }
723
724 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800725 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800726 }
727
728 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700729 boolean keyDispatchingTimedOut(String reason, int windowPid) {
730 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800731 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800732
733 @Override
734 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700735 return "AppWindowContainerController{"
736 + " token=" + mToken
737 + " mContainer=" + mContainer
738 + " mListener=" + mListener
739 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800740 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800741}