blob: 73732dd83e6eb1cc878da0de9bf2c5ecf4582693 [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
22import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080023import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
24import 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 Ogunwale55ddf8f2017-03-20 08:56:38 -070035import android.graphics.Rect;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080036import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080037import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080038import android.os.IBinder;
Sudheer Shankac766db02017-06-12 10:37:29 -070039import android.os.Looper;
40import android.os.Message;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080041import android.util.Slog;
42import android.view.IApplicationToken;
43
Winson Chung30480042017-01-26 10:55:34 -080044import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080045import com.android.server.AttributeCache;
Adrian Roose99bc052017-11-20 17:55:31 +010046import com.android.server.policy.WindowManagerPolicy.StartingSurface;
47
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080048/**
49 * Controller for the app window token container. This is created by activity manager to link
50 * activity records to the app window token container they use in window manager.
51 *
52 * Test class: {@link AppWindowContainerControllerTests}
53 */
54public class AppWindowContainerController
55 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
56
Jorim Jaggi02886a82016-12-06 09:10:06 -080057 private static final int STARTING_WINDOW_TYPE_NONE = 0;
58 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
59 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
60
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080061 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010062 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080063
Sudheer Shankac766db02017-06-12 10:37:29 -070064 private final class H extends Handler {
65 public static final int NOTIFY_WINDOWS_DRAWN = 1;
66 public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080067
Sudheer Shankac766db02017-06-12 10:37:29 -070068 public H(Looper looper) {
69 super(looper);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080070 }
Sudheer Shankac766db02017-06-12 10:37:29 -070071
72 @Override
73 public void handleMessage(Message msg) {
74 switch (msg.what) {
75 case NOTIFY_WINDOWS_DRAWN:
76 if (mListener == null) {
77 return;
78 }
79 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
80 + AppWindowContainerController.this.mToken);
81 mListener.onWindowsDrawn(msg.getWhen());
82 break;
83 case NOTIFY_STARTING_WINDOW_DRAWN:
84 if (mListener == null) {
85 return;
86 }
87 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
88 + AppWindowContainerController.this.mToken);
89 mListener.onStartingWindowDrawn(msg.getWhen());
90 break;
91 default:
92 break;
93 }
94 }
95 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080096
97 private final Runnable mOnWindowsVisible = () -> {
98 if (mListener == null) {
99 return;
100 }
101 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
102 + AppWindowContainerController.this.mToken);
103 mListener.onWindowsVisible();
104 };
105
106 private final Runnable mOnWindowsGone = () -> {
107 if (mListener == null) {
108 return;
109 }
110 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
111 + AppWindowContainerController.this.mToken);
112 mListener.onWindowsGone();
113 };
114
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800115 private final Runnable mAddStartingWindow = () -> {
116 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100117 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800118
119 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100120 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200121 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
122 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100123 return;
124 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800125 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100126 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800127 }
128
129 if (startingData == null) {
130 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200131 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
132 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800133 return;
134 }
135
136 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100137 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800138
Jorim Jaggi02886a82016-12-06 09:10:06 -0800139 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800140 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100141 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800142 } catch (Exception e) {
143 Slog.w(TAG_WM, "Exception when adding starting window", e);
144 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800145 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800146 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800147 synchronized(mWindowMap) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200148 // If the window was successfully added, then
149 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100150 if (container.removed || container.startingData == null) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200151 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
152 "Aborted starting " + container
153 + ": removed=" + container.removed
154 + " startingData=" + container.startingData);
155 container.startingWindow = null;
156 container.startingData = null;
157 abort = true;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800158 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100159 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800160 }
161 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
162 "Added starting " + mContainer
163 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100164 + container.startingWindow + " startingView="
165 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800166 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800167 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100168 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800169 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200170 } else if (DEBUG_STARTING_WINDOW) {
171 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800172 }
173 };
174
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800175 public AppWindowContainerController(TaskWindowContainerController taskController,
176 IApplicationToken token, AppWindowContainerListener listener, int index,
177 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800178 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Bryce Leef3c6a472017-11-14 14:53:06 -0800179 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800180 this(taskController, token, listener, index, requestedOrientation, fullscreen,
181 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800182 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
183 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Bryce Leef3c6a472017-11-14 14:53:06 -0800184 WindowManagerService.getInstance());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800185 }
186
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800187 public AppWindowContainerController(TaskWindowContainerController taskController,
188 IApplicationToken token, AppWindowContainerListener listener, int index,
189 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800190 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
191 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Bryce Leef3c6a472017-11-14 14:53:06 -0800192 WindowManagerService service) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800193 super(listener, service);
Sudheer Shankac766db02017-06-12 10:37:29 -0700194 mHandler = new H(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800195 mToken = token;
196 synchronized(mWindowMap) {
197 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
198 if (atoken != null) {
199 // TODO: Should this throw an exception instead?
200 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
201 return;
202 }
203
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800204 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800205 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800206 throw new IllegalArgumentException("AppWindowContainerController: invalid "
207 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800208 }
209
Winson Chung30480042017-01-26 10:55:34 -0800210 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800211 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
212 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Bryce Leef3c6a472017-11-14 14:53:06 -0800213 alwaysFocusable, this);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800214 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800215 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800216 task.addChild(atoken, index);
217 }
218 }
219
Winson Chung30480042017-01-26 10:55:34 -0800220 @VisibleForTesting
221 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
222 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
223 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
224 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Bryce Leef3c6a472017-11-14 14:53:06 -0800225 boolean alwaysFocusable, AppWindowContainerController controller) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100226 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800227 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
228 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Bryce Leef3c6a472017-11-14 14:53:06 -0800229 controller);
Winson Chung30480042017-01-26 10:55:34 -0800230 }
231
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800232 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800233 synchronized(mWindowMap) {
234 final DisplayContent dc = mRoot.getDisplayContent(displayId);
235 if (dc == null) {
236 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
237 + mToken + " from non-existing displayId=" + displayId);
238 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800239 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800240 dc.removeAppToken(mToken.asBinder());
241 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800242 }
243 }
244
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800245 @Override
246 public void removeContainer() {
247 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800248 }
249
Winson Chung30480042017-01-26 10:55:34 -0800250 public void reparent(TaskWindowContainerController taskController, int position) {
251 synchronized (mWindowMap) {
252 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
253 + " to task=" + taskController + " at " + position);
254 if (mContainer == null) {
255 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
256 "reparent: could not find app token=" + mToken);
257 return;
258 }
259 final Task task = taskController.mContainer;
260 if (task == null) {
261 throw new IllegalArgumentException("reparent: could not find task="
262 + taskController);
263 }
264 mContainer.reparent(task, position);
265 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
266 }
267 }
268
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800269 public Configuration setOrientation(int requestedOrientation, int displayId,
270 Configuration displayConfig, boolean freezeScreenIfNeeded) {
271 synchronized(mWindowMap) {
272 if (mContainer == null) {
273 Slog.w(TAG_WM,
274 "Attempted to set orientation of non-existing app token: " + mToken);
275 return null;
276 }
277
278 mContainer.setOrientation(requestedOrientation);
279
280 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
281 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
282
283 }
284 }
285
286 public int getOrientation() {
287 synchronized(mWindowMap) {
288 if (mContainer == null) {
289 return SCREEN_ORIENTATION_UNSPECIFIED;
290 }
291
292 return mContainer.getOrientationIgnoreVisibility();
293 }
294 }
295
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100296 public void setDisablePreviewScreenshots(boolean disable) {
297 synchronized (mWindowMap) {
298 if (mContainer == null) {
299 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
300 + " token: " + mToken);
301 return;
302 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200303 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100304 }
305 }
306
Tim Murray68ed8442017-08-29 23:21:27 +0000307 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800308 synchronized(mWindowMap) {
309 if (mContainer == null) {
310 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
311 + mToken);
312 return;
313 }
314
315 final AppWindowToken wtoken = mContainer;
316
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700317 // Don't set visibility to false if we were already not visible. This prevents WM from
318 // adding the app to the closing app list which doesn't make sense for something that is
319 // already not visible. However, set visibility to true even if we are already visible.
320 // This makes sure the app is added to the opening apps list so that the right
321 // transition can be selected.
322 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
323 // concept of setting visibility...
324 if (!visible && wtoken.hiddenRequested) {
325
326 if (!deferHidingClient && wtoken.mDeferHidingClient) {
327 // We previously deferred telling the client to hide itself when visibility was
328 // initially set to false. Now we would like it to hide, so go ahead and set it.
329 wtoken.mDeferHidingClient = deferHidingClient;
330 wtoken.setClientHidden(true);
331 }
332 return;
333 }
334
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800335 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
336 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200337 + " hidden=" + wtoken.isHidden() + " hiddenRequested="
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800338 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
339
340 mService.mOpeningApps.remove(wtoken);
341 mService.mClosingApps.remove(wtoken);
342 wtoken.waitingToShow = false;
343 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700344 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800345
346 if (!visible) {
347 // If the app is dead while it was visible, we kept its dead window on screen.
348 // Now that the app is going invisible, we can remove it. It will be restarted
349 // if made visible again.
350 wtoken.removeDeadWindows();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800351 } else {
352 if (!mService.mAppTransition.isTransitionSet()
353 && mService.mAppTransition.isReady()) {
354 // Add the app mOpeningApps if transition is unset but ready. This means
355 // we're doing a screen freeze, and the unfreeze will wait for all opening
356 // apps to be ready.
357 mService.mOpeningApps.add(wtoken);
358 }
359 wtoken.startingMoved = false;
360 // If the token is currently hidden (should be the common case), or has been
361 // stopped, then we need to set up to wait for its windows to be ready.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200362 if (wtoken.isHidden() || wtoken.mAppStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800363 wtoken.clearAllDrawn();
364
365 // If the app was already visible, don't reset the waitingToShow state.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200366 if (wtoken.isHidden()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800367 wtoken.waitingToShow = true;
368 }
369
Wale Ogunwale89973222017-04-23 18:39:45 -0700370 if (wtoken.isClientHidden()) {
371 // In the case where we are making an app visible but holding off for a
372 // transition, we still need to tell the client to make its windows visible
373 // so they get drawn. Otherwise, we will wait on performing the transition
374 // until all windows have been drawn, they never will be, and we are sad.
375 wtoken.setClientHidden(false);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800376 }
377 }
378 wtoken.requestUpdateWallpaperIfNeeded();
379
380 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
381 wtoken.mAppStopped = false;
382 }
383
384 // If we are preparing an app transition, then delay changing
385 // the visibility of this token until we execute that transition.
David Stevensf62360c2017-03-16 19:00:20 -0700386 if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800387 wtoken.inPendingTransaction = true;
388 if (visible) {
389 mService.mOpeningApps.add(wtoken);
390 wtoken.mEnteringAnimation = true;
391 } else {
392 mService.mClosingApps.add(wtoken);
393 wtoken.mEnteringAnimation = false;
394 }
395 if (mService.mAppTransition.getAppTransition()
396 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
397 // We're launchingBehind, add the launching activity to mOpeningApps.
398 final WindowState win =
399 mService.getDefaultDisplayContentLocked().findFocusedWindow();
400 if (win != null) {
401 final AppWindowToken focusedToken = win.mAppToken;
402 if (focusedToken != null) {
403 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
404 + " adding " + focusedToken + " to mOpeningApps");
405 // Force animation to be loaded.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200406 focusedToken.setHidden(true);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800407 mService.mOpeningApps.add(focusedToken);
408 }
409 }
410 }
411 return;
412 }
413
414 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
415 wtoken.updateReportedVisibilityLocked();
416 }
417 }
418
419 /**
420 * Notifies that we launched an app that might be visible or not visible depending on what kind
421 * of Keyguard flags it's going to set on its windows.
422 */
423 public void notifyUnknownVisibilityLaunched() {
424 synchronized(mWindowMap) {
425 if (mContainer != null) {
426 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
427 }
428 }
429 }
430
431 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
432 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700433 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700434 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800435 synchronized(mWindowMap) {
436 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200437 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
438 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
439 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800440
441 if (mContainer == null) {
442 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
443 return false;
444 }
445
446 // If the display is frozen, we won't do anything until the actual window is
447 // displayed so there is no reason to put in the starting window.
David Stevensf62360c2017-03-16 19:00:20 -0700448 if (!mContainer.okToDisplay()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800449 return false;
450 }
451
452 if (mContainer.startingData != null) {
453 return false;
454 }
455
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700456 final WindowState mainWin = mContainer.findMainWindow();
Jorim Jaggie6b1b3b2017-07-24 16:44:18 +0200457 if (mainWin != null && mainWin.mWinAnimator.getShown()) {
458 // App already has a visible window...why would you want a starting window?
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700459 return false;
460 }
461
Jorim Jaggi42befc62017-06-13 11:54:04 -0700462 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
463 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
464 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggibae01b12017-04-11 16:29:10 -0700465 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700466 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800467
468 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700469 return createSnapshot(snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800470 }
471
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800472 // If this is a translucent window, then don't show a starting window -- the current
473 // effect (a full-screen opaque starting window that fades away to the real contents
474 // when it is ready) does not work for this.
475 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
476 + Integer.toHexString(theme));
477 if (theme != 0) {
478 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
479 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
480 if (ent == null) {
481 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
482 // see that.
483 return false;
484 }
485 final boolean windowIsTranslucent = ent.array.getBoolean(
486 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
487 final boolean windowIsFloating = ent.array.getBoolean(
488 com.android.internal.R.styleable.Window_windowIsFloating, false);
489 final boolean windowShowWallpaper = ent.array.getBoolean(
490 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
491 final boolean windowDisableStarting = ent.array.getBoolean(
492 com.android.internal.R.styleable.Window_windowDisablePreview, false);
493 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
494 + " Floating=" + windowIsFloating
495 + " ShowWallpaper=" + windowShowWallpaper);
496 if (windowIsTranslucent) {
497 return false;
498 }
499 if (windowIsFloating || windowDisableStarting) {
500 return false;
501 }
502 if (windowShowWallpaper) {
503 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
504 == null) {
505 // If this theme is requesting a wallpaper, and the wallpaper
506 // is not currently visible, then this effectively serves as
507 // an opaque window and our starting window transition animation
508 // can still work. We just need to make sure the starting window
509 // is also showing the wallpaper.
510 windowFlags |= FLAG_SHOW_WALLPAPER;
511 } else {
512 return false;
513 }
514 }
515 }
516
517 if (mContainer.transferStartingWindow(transferFrom)) {
518 return true;
519 }
520
Jorim Jaggi02886a82016-12-06 09:10:06 -0800521 // There is no existing starting window, and we don't want to create a splash screen, so
522 // that's it!
523 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800524 return false;
525 }
526
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200527 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100528 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800529 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
530 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800531 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800532 }
533 return true;
534 }
535
Jorim Jaggibae01b12017-04-11 16:29:10 -0700536 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700537 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
538 TaskSnapshot snapshot) {
Matthew Ng606dd802017-06-05 14:06:32 -0700539 if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
540 // TODO(b/34099271): Remove this statement to add back the starting window and figure
541 // out why it causes flickering, the starting window appears over the thumbnail while
542 // the docked from recents transition occurs
543 return STARTING_WINDOW_TYPE_NONE;
544 } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800545 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700546 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700547 return snapshot == null ? STARTING_WINDOW_TYPE_NONE
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400548 : snapshotOrientationSameAsTask(snapshot) || fromRecents
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700549 ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800550 } else {
551 return STARTING_WINDOW_TYPE_NONE;
552 }
553 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800554
Jorim Jaggi02886a82016-12-06 09:10:06 -0800555 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800556 // Note: we really want to do sendMessageAtFrontOfQueue() because we
557 // want to process the message ASAP, before any other queued
558 // messages.
559 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100560 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800561 }
562
Jorim Jaggi42befc62017-06-13 11:54:04 -0700563 private boolean createSnapshot(TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800564 if (snapshot == null) {
565 return false;
566 }
567
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200568 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200569 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800570 scheduleAddStartingWindow();
571 return true;
572 }
573
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400574 private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700575 if (snapshot == null) {
576 return false;
577 }
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400578 return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
Jorim Jaggi42befc62017-06-13 11:54:04 -0700579 }
580
Jorim Jaggi19be6052017-08-03 18:33:43 +0200581 public void removeStartingWindow() {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800582 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800583 if (mContainer.startingWindow == null) {
584 if (mContainer.startingData != null) {
585 // Starting window has not been added yet, but it is scheduled to be added.
586 // Go ahead and cancel the request.
587 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
588 "Clearing startingData for token=" + mContainer);
589 mContainer.startingData = null;
590 }
591 return;
592 }
593
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700594 final StartingSurface surface;
595 if (mContainer.startingData != null) {
596 surface = mContainer.startingSurface;
597 mContainer.startingData = null;
598 mContainer.startingSurface = null;
599 mContainer.startingWindow = null;
600 mContainer.startingDisplayed = false;
Seigo Nonakaeafe7372017-08-16 12:39:49 -0700601 if (surface == null) {
602 if (DEBUG_STARTING_WINDOW) {
603 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
604 + "remove");
605 }
606 return;
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700607 }
608 } else {
609 if (DEBUG_STARTING_WINDOW) {
610 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
611 + mContainer);
612 }
613 return;
614 }
615
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200616 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700617 + " startingWindow=" + mContainer.startingWindow
618 + " startingView=" + mContainer.startingSurface);
Jorim Jaggia3382192017-07-18 14:33:21 +0200619
620 // Use the same thread to remove the window as we used to add it, as otherwise we end up
621 // with things in the view hierarchy being called from different threads.
Jorim Jaggi8829cf12017-09-05 12:28:52 +0200622 mService.mAnimationHandler.post(() -> {
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700623 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
624 try {
625 surface.remove();
626 } catch (Exception e) {
627 Slog.w(TAG_WM, "Exception when removing starting window", e);
628 }
629 });
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800630 }
631 }
632
633 public void pauseKeyDispatching() {
634 synchronized (mWindowMap) {
635 if (mContainer != null) {
636 mService.mInputMonitor.pauseDispatchingLw(mContainer);
637 }
638 }
639 }
640
641 public void resumeKeyDispatching() {
642 synchronized (mWindowMap) {
643 if (mContainer != null) {
644 mService.mInputMonitor.resumeDispatchingLw(mContainer);
645 }
646 }
647 }
648
Jorim Jaggibae01b12017-04-11 16:29:10 -0700649 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800650 synchronized(mWindowMap) {
651 if (mContainer == null) {
652 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
653 return;
654 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700655 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800656 }
657 }
658
659 public void notifyAppStopped() {
660 synchronized(mWindowMap) {
661 if (mContainer == null) {
662 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
663 + mToken);
664 return;
665 }
666 mContainer.notifyAppStopped();
667 }
668 }
669
670 public void startFreezingScreen(int configChanges) {
671 synchronized(mWindowMap) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800672 if (mContainer == null) {
673 Slog.w(TAG_WM,
674 "Attempted to freeze screen with non-existing app token: " + mContainer);
675 return;
676 }
David Stevensf62360c2017-03-16 19:00:20 -0700677
678 if (configChanges == 0 && mContainer.okToDisplay()) {
679 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
680 return;
681 }
682
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800683 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800684 }
685 }
686
687 public void stopFreezingScreen(boolean force) {
688 synchronized(mWindowMap) {
689 if (mContainer == null) {
690 return;
691 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800692 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200693 + mContainer.isHidden() + " freezing=" + mContainer.mAppAnimator.freezingScreen);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800694 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800695 }
696 }
697
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800698 void reportStartingWindowDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700699 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800700 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800701
702 void reportWindowsDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700703 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800704 }
705
706 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800707 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800708 }
709
710 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800711 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800712 }
713
714 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700715 boolean keyDispatchingTimedOut(String reason, int windowPid) {
716 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800717 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800718
719 @Override
720 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700721 return "AppWindowContainerController{"
722 + " token=" + mToken
723 + " mContainer=" + mContainer
724 + " mListener=" + mListener
725 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800726 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800727}