blob: 84fafe261d35353200cca4d504d2ac186e982c6f [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;
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
29import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
30import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
31import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080032
Jorim Jaggie2c77f92016-12-29 14:57:22 +010033import android.app.ActivityManager.TaskSnapshot;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080034import android.content.res.CompatibilityInfo;
35import android.content.res.Configuration;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080036import android.graphics.Bitmap;
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -070037import android.graphics.Rect;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080038import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080039import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080040import android.os.IBinder;
Sudheer Shankac766db02017-06-12 10:37:29 -070041import android.os.Looper;
42import android.os.Message;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080043import android.os.Trace;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080044import android.util.Slog;
Jorim Jaggi42befc62017-06-13 11:54:04 -070045import android.view.DisplayInfo;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080046import android.view.IApplicationToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080047import android.view.WindowManagerPolicy.StartingSurface;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080048
Winson Chung30480042017-01-26 10:55:34 -080049import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080050import com.android.server.AttributeCache;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080051/**
52 * Controller for the app window token container. This is created by activity manager to link
53 * activity records to the app window token container they use in window manager.
54 *
55 * Test class: {@link AppWindowContainerControllerTests}
56 */
57public class AppWindowContainerController
58 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
59
Jorim Jaggi02886a82016-12-06 09:10:06 -080060 private static final int STARTING_WINDOW_TYPE_NONE = 0;
61 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
62 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
63
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080064 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010065 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080066
Sudheer Shankac766db02017-06-12 10:37:29 -070067 private final class H extends Handler {
68 public static final int NOTIFY_WINDOWS_DRAWN = 1;
69 public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080070
Sudheer Shankac766db02017-06-12 10:37:29 -070071 public H(Looper looper) {
72 super(looper);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080073 }
Sudheer Shankac766db02017-06-12 10:37:29 -070074
75 @Override
76 public void handleMessage(Message msg) {
77 switch (msg.what) {
78 case NOTIFY_WINDOWS_DRAWN:
79 if (mListener == null) {
80 return;
81 }
82 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
83 + AppWindowContainerController.this.mToken);
84 mListener.onWindowsDrawn(msg.getWhen());
85 break;
86 case NOTIFY_STARTING_WINDOW_DRAWN:
87 if (mListener == null) {
88 return;
89 }
90 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
91 + AppWindowContainerController.this.mToken);
92 mListener.onStartingWindowDrawn(msg.getWhen());
93 break;
94 default:
95 break;
96 }
97 }
98 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080099
100 private final Runnable mOnWindowsVisible = () -> {
101 if (mListener == null) {
102 return;
103 }
104 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
105 + AppWindowContainerController.this.mToken);
106 mListener.onWindowsVisible();
107 };
108
109 private final Runnable mOnWindowsGone = () -> {
110 if (mListener == null) {
111 return;
112 }
113 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
114 + AppWindowContainerController.this.mToken);
115 mListener.onWindowsGone();
116 };
117
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800118 private final Runnable mAddStartingWindow = () -> {
119 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100120 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800121
122 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100123 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200124 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
125 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100126 return;
127 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800128 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100129 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800130 }
131
132 if (startingData == null) {
133 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200134 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
135 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800136 return;
137 }
138
139 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100140 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800141
Jorim Jaggi02886a82016-12-06 09:10:06 -0800142 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800143 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100144 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800145 } catch (Exception e) {
146 Slog.w(TAG_WM, "Exception when adding starting window", e);
147 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800148 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800149 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800150 synchronized(mWindowMap) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200151 // If the window was successfully added, then
152 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100153 if (container.removed || container.startingData == null) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200154 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
155 "Aborted starting " + container
156 + ": removed=" + container.removed
157 + " startingData=" + container.startingData);
158 container.startingWindow = null;
159 container.startingData = null;
160 abort = true;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800161 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100162 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800163 }
164 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
165 "Added starting " + mContainer
166 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100167 + container.startingWindow + " startingView="
168 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800169 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800170 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100171 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800172 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200173 } else if (DEBUG_STARTING_WINDOW) {
174 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800175 }
176 };
177
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800178 public AppWindowContainerController(TaskWindowContainerController taskController,
179 IApplicationToken token, AppWindowContainerListener listener, int index,
180 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800181 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700182 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
183 Configuration overrideConfig, Rect bounds) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800184 this(taskController, token, listener, index, requestedOrientation, fullscreen,
185 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800186 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
187 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700188 WindowManagerService.getInstance(), overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800189 }
190
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800191 public AppWindowContainerController(TaskWindowContainerController taskController,
192 IApplicationToken token, AppWindowContainerListener listener, int index,
193 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800194 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
195 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700196 WindowManagerService service, Configuration overrideConfig, Rect bounds) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800197 super(listener, service);
Sudheer Shankac766db02017-06-12 10:37:29 -0700198 mHandler = new H(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800199 mToken = token;
200 synchronized(mWindowMap) {
201 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
202 if (atoken != null) {
203 // TODO: Should this throw an exception instead?
204 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
205 return;
206 }
207
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800208 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800209 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800210 throw new IllegalArgumentException("AppWindowContainerController: invalid "
211 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800212 }
213
Winson Chung30480042017-01-26 10:55:34 -0800214 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800215 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
216 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700217 alwaysFocusable, this, overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800218 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800219 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800220 task.addChild(atoken, index);
221 }
222 }
223
Winson Chung30480042017-01-26 10:55:34 -0800224 @VisibleForTesting
225 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
226 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
227 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
228 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700229 boolean alwaysFocusable, AppWindowContainerController controller,
230 Configuration overrideConfig, Rect bounds) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100231 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800232 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
233 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700234 controller, overrideConfig, bounds);
Winson Chung30480042017-01-26 10:55:34 -0800235 }
236
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800237 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800238 synchronized(mWindowMap) {
239 final DisplayContent dc = mRoot.getDisplayContent(displayId);
240 if (dc == null) {
241 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
242 + mToken + " from non-existing displayId=" + displayId);
243 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800244 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800245 dc.removeAppToken(mToken.asBinder());
246 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800247 }
248 }
249
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800250 @Override
251 public void removeContainer() {
252 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800253 }
254
Winson Chung30480042017-01-26 10:55:34 -0800255 public void reparent(TaskWindowContainerController taskController, int position) {
256 synchronized (mWindowMap) {
257 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
258 + " to task=" + taskController + " at " + position);
259 if (mContainer == null) {
260 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
261 "reparent: could not find app token=" + mToken);
262 return;
263 }
264 final Task task = taskController.mContainer;
265 if (task == null) {
266 throw new IllegalArgumentException("reparent: could not find task="
267 + taskController);
268 }
269 mContainer.reparent(task, position);
270 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
271 }
272 }
273
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800274 public Configuration setOrientation(int requestedOrientation, int displayId,
275 Configuration displayConfig, boolean freezeScreenIfNeeded) {
276 synchronized(mWindowMap) {
277 if (mContainer == null) {
278 Slog.w(TAG_WM,
279 "Attempted to set orientation of non-existing app token: " + mToken);
280 return null;
281 }
282
283 mContainer.setOrientation(requestedOrientation);
284
285 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
286 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
287
288 }
289 }
290
291 public int getOrientation() {
292 synchronized(mWindowMap) {
293 if (mContainer == null) {
294 return SCREEN_ORIENTATION_UNSPECIFIED;
295 }
296
297 return mContainer.getOrientationIgnoreVisibility();
298 }
299 }
300
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700301 // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
302 // a generic way to set override config. Need to untangle current ways the override config is
303 // currently set for tasks and displays before we are doing that though.
304 public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
305 synchronized(mWindowMap) {
306 if (mContainer != null) {
307 mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
308 }
309 }
310 }
311
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100312 public void setDisablePreviewScreenshots(boolean disable) {
313 synchronized (mWindowMap) {
314 if (mContainer == null) {
315 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
316 + " token: " + mToken);
317 return;
318 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200319 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100320 }
321 }
322
Wale Ogunwale89973222017-04-23 18:39:45 -0700323 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800324 synchronized(mWindowMap) {
325 if (mContainer == null) {
326 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
327 + mToken);
328 return;
329 }
330
331 final AppWindowToken wtoken = mContainer;
332
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700333 // Don't set visibility to false if we were already not visible. This prevents WM from
334 // adding the app to the closing app list which doesn't make sense for something that is
335 // already not visible. However, set visibility to true even if we are already visible.
336 // This makes sure the app is added to the opening apps list so that the right
337 // transition can be selected.
338 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
339 // concept of setting visibility...
340 if (!visible && wtoken.hiddenRequested) {
341
342 if (!deferHidingClient && wtoken.mDeferHidingClient) {
343 // We previously deferred telling the client to hide itself when visibility was
344 // initially set to false. Now we would like it to hide, so go ahead and set it.
345 wtoken.mDeferHidingClient = deferHidingClient;
346 wtoken.setClientHidden(true);
347 }
348 return;
349 }
350
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800351 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
352 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
353 + " hidden=" + wtoken.hidden + " hiddenRequested="
354 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
355
356 mService.mOpeningApps.remove(wtoken);
357 mService.mClosingApps.remove(wtoken);
358 wtoken.waitingToShow = false;
359 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700360 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800361
362 if (!visible) {
363 // If the app is dead while it was visible, we kept its dead window on screen.
364 // Now that the app is going invisible, we can remove it. It will be restarted
365 // if made visible again.
366 wtoken.removeDeadWindows();
367 wtoken.setVisibleBeforeClientHidden();
Jorim Jaggi45ca0542017-05-30 16:16:01 -0700368 mService.mUnknownAppVisibilityController.appRemovedOrHidden(wtoken);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800369 } else {
370 if (!mService.mAppTransition.isTransitionSet()
371 && mService.mAppTransition.isReady()) {
372 // Add the app mOpeningApps if transition is unset but ready. This means
373 // we're doing a screen freeze, and the unfreeze will wait for all opening
374 // apps to be ready.
375 mService.mOpeningApps.add(wtoken);
376 }
377 wtoken.startingMoved = false;
378 // If the token is currently hidden (should be the common case), or has been
379 // stopped, then we need to set up to wait for its windows to be ready.
380 if (wtoken.hidden || wtoken.mAppStopped) {
381 wtoken.clearAllDrawn();
382
383 // If the app was already visible, don't reset the waitingToShow state.
384 if (wtoken.hidden) {
385 wtoken.waitingToShow = true;
386 }
387
Wale Ogunwale89973222017-04-23 18:39:45 -0700388 if (wtoken.isClientHidden()) {
389 // In the case where we are making an app visible but holding off for a
390 // transition, we still need to tell the client to make its windows visible
391 // so they get drawn. Otherwise, we will wait on performing the transition
392 // until all windows have been drawn, they never will be, and we are sad.
393 wtoken.setClientHidden(false);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800394 }
395 }
396 wtoken.requestUpdateWallpaperIfNeeded();
397
398 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
399 wtoken.mAppStopped = false;
400 }
401
402 // If we are preparing an app transition, then delay changing
403 // the visibility of this token until we execute that transition.
Adrian Roose94c15c2017-05-09 13:17:54 -0700404 if (mService.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800405 // A dummy animation is a placeholder animation which informs others that an
406 // animation is going on (in this case an application transition). If the animation
407 // was transferred from another application/animator, no dummy animator should be
408 // created since an animation is already in progress.
409 if (wtoken.mAppAnimator.usingTransferredAnimation
410 && wtoken.mAppAnimator.animation == null) {
411 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
412 + ", using null transferred animation!");
413 }
414 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
415 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
416 if (DEBUG_APP_TRANSITIONS) Slog.v(
417 TAG_WM, "Setting dummy animation on: " + wtoken);
418 wtoken.mAppAnimator.setDummyAnimation();
419 }
420 wtoken.inPendingTransaction = true;
421 if (visible) {
422 mService.mOpeningApps.add(wtoken);
423 wtoken.mEnteringAnimation = true;
424 } else {
425 mService.mClosingApps.add(wtoken);
426 wtoken.mEnteringAnimation = false;
427 }
428 if (mService.mAppTransition.getAppTransition()
429 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
430 // We're launchingBehind, add the launching activity to mOpeningApps.
431 final WindowState win =
432 mService.getDefaultDisplayContentLocked().findFocusedWindow();
433 if (win != null) {
434 final AppWindowToken focusedToken = win.mAppToken;
435 if (focusedToken != null) {
436 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
437 + " adding " + focusedToken + " to mOpeningApps");
438 // Force animation to be loaded.
439 focusedToken.hidden = true;
440 mService.mOpeningApps.add(focusedToken);
441 }
442 }
443 }
444 return;
445 }
446
447 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
448 wtoken.updateReportedVisibilityLocked();
449 }
450 }
451
452 /**
453 * Notifies that we launched an app that might be visible or not visible depending on what kind
454 * of Keyguard flags it's going to set on its windows.
455 */
456 public void notifyUnknownVisibilityLaunched() {
457 synchronized(mWindowMap) {
458 if (mContainer != null) {
459 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
460 }
461 }
462 }
463
464 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
465 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700466 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700467 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800468 synchronized(mWindowMap) {
469 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200470 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
471 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
472 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800473
474 if (mContainer == null) {
475 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
476 return false;
477 }
478
479 // If the display is frozen, we won't do anything until the actual window is
480 // displayed so there is no reason to put in the starting window.
481 if (!mService.okToDisplay()) {
482 return false;
483 }
484
485 if (mContainer.startingData != null) {
486 return false;
487 }
488
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700489 final WindowState mainWin = mContainer.findMainWindow();
490 if (mainWin != null && mainWin.isVisible() && mainWin.isDrawnLw()) {
491 // App already has a visible window that is drawn...why would you want a starting
492 // window?
493 return false;
494 }
495
Jorim Jaggi42befc62017-06-13 11:54:04 -0700496 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
497 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
498 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggibae01b12017-04-11 16:29:10 -0700499 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700500 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800501
502 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700503 return createSnapshot(snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800504 }
505
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800506 // If this is a translucent window, then don't show a starting window -- the current
507 // effect (a full-screen opaque starting window that fades away to the real contents
508 // when it is ready) does not work for this.
509 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
510 + Integer.toHexString(theme));
511 if (theme != 0) {
512 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
513 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
514 if (ent == null) {
515 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
516 // see that.
517 return false;
518 }
519 final boolean windowIsTranslucent = ent.array.getBoolean(
520 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
521 final boolean windowIsFloating = ent.array.getBoolean(
522 com.android.internal.R.styleable.Window_windowIsFloating, false);
523 final boolean windowShowWallpaper = ent.array.getBoolean(
524 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
525 final boolean windowDisableStarting = ent.array.getBoolean(
526 com.android.internal.R.styleable.Window_windowDisablePreview, false);
527 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
528 + " Floating=" + windowIsFloating
529 + " ShowWallpaper=" + windowShowWallpaper);
530 if (windowIsTranslucent) {
531 return false;
532 }
533 if (windowIsFloating || windowDisableStarting) {
534 return false;
535 }
536 if (windowShowWallpaper) {
537 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
538 == null) {
539 // If this theme is requesting a wallpaper, and the wallpaper
540 // is not currently visible, then this effectively serves as
541 // an opaque window and our starting window transition animation
542 // can still work. We just need to make sure the starting window
543 // is also showing the wallpaper.
544 windowFlags |= FLAG_SHOW_WALLPAPER;
545 } else {
546 return false;
547 }
548 }
549 }
550
551 if (mContainer.transferStartingWindow(transferFrom)) {
552 return true;
553 }
554
Jorim Jaggi02886a82016-12-06 09:10:06 -0800555 // There is no existing starting window, and we don't want to create a splash screen, so
556 // that's it!
557 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800558 return false;
559 }
560
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200561 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100562 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800563 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
564 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800565 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800566 }
567 return true;
568 }
569
Jorim Jaggibae01b12017-04-11 16:29:10 -0700570 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700571 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
572 TaskSnapshot snapshot) {
Matthew Ng606dd802017-06-05 14:06:32 -0700573 if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
574 // TODO(b/34099271): Remove this statement to add back the starting window and figure
575 // out why it causes flickering, the starting window appears over the thumbnail while
576 // the docked from recents transition occurs
577 return STARTING_WINDOW_TYPE_NONE;
578 } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800579 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700580 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700581 return snapshot == null ? STARTING_WINDOW_TYPE_NONE
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400582 : snapshotOrientationSameAsTask(snapshot) || fromRecents
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700583 ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800584 } else {
585 return STARTING_WINDOW_TYPE_NONE;
586 }
587 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800588
Jorim Jaggi02886a82016-12-06 09:10:06 -0800589 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800590 // Note: we really want to do sendMessageAtFrontOfQueue() because we
591 // want to process the message ASAP, before any other queued
592 // messages.
593 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100594 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800595 }
596
Jorim Jaggi42befc62017-06-13 11:54:04 -0700597 private boolean createSnapshot(TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800598 if (snapshot == null) {
599 return false;
600 }
601
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200602 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200603 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800604 scheduleAddStartingWindow();
605 return true;
606 }
607
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400608 private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700609 if (snapshot == null) {
610 return false;
611 }
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400612 return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
Jorim Jaggi42befc62017-06-13 11:54:04 -0700613 }
614
Wale Ogunwale2c596d52017-07-06 15:30:55 -0700615 /**
616 * Remove starting window if the app is currently hidden. It is possible the starting window is
617 * part of its app exit transition animation in which case we delay hiding the app token. The
618 * method allows for removal when window manager has set the app token to hidden.
619 */
620 public void removeHiddenStartingWindow() {
621 synchronized (mWindowMap) {
622 if (!mContainer.hidden) {
623 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Starting window app still visible."
624 + " Ignoring remove request.");
625 return;
626 }
627 removeStartingWindow();
628 }
629 }
630
631 void removeStartingWindow() {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800632 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800633 if (mContainer.startingWindow == null) {
634 if (mContainer.startingData != null) {
635 // Starting window has not been added yet, but it is scheduled to be added.
636 // Go ahead and cancel the request.
637 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
638 "Clearing startingData for token=" + mContainer);
639 mContainer.startingData = null;
640 }
641 return;
642 }
643
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700644 final StartingSurface surface;
645 if (mContainer.startingData != null) {
646 surface = mContainer.startingSurface;
647 mContainer.startingData = null;
648 mContainer.startingSurface = null;
649 mContainer.startingWindow = null;
650 mContainer.startingDisplayed = false;
651 if (surface == null && DEBUG_STARTING_WINDOW) {
652 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
653 + "remove");
654 }
655 } else {
656 if (DEBUG_STARTING_WINDOW) {
657 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
658 + mContainer);
659 }
660 return;
661 }
662
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200663 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700664 + " startingWindow=" + mContainer.startingWindow
665 + " startingView=" + mContainer.startingSurface);
Jorim Jaggia3382192017-07-18 14:33:21 +0200666
667 // Use the same thread to remove the window as we used to add it, as otherwise we end up
668 // with things in the view hierarchy being called from different threads.
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700669 mHandler.post(() -> {
670 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
671 try {
672 surface.remove();
673 } catch (Exception e) {
674 Slog.w(TAG_WM, "Exception when removing starting window", e);
675 }
676 });
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800677 }
678 }
679
680 public void pauseKeyDispatching() {
681 synchronized (mWindowMap) {
682 if (mContainer != null) {
683 mService.mInputMonitor.pauseDispatchingLw(mContainer);
684 }
685 }
686 }
687
688 public void resumeKeyDispatching() {
689 synchronized (mWindowMap) {
690 if (mContainer != null) {
691 mService.mInputMonitor.resumeDispatchingLw(mContainer);
692 }
693 }
694 }
695
Jorim Jaggibae01b12017-04-11 16:29:10 -0700696 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800697 synchronized(mWindowMap) {
698 if (mContainer == null) {
699 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
700 return;
701 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700702 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800703 }
704 }
705
706 public void notifyAppStopped() {
707 synchronized(mWindowMap) {
708 if (mContainer == null) {
709 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
710 + mToken);
711 return;
712 }
713 mContainer.notifyAppStopped();
714 }
715 }
716
717 public void startFreezingScreen(int configChanges) {
718 synchronized(mWindowMap) {
719 if (configChanges == 0 && mService.okToDisplay()) {
720 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
721 return;
722 }
723
724 if (mContainer == null) {
725 Slog.w(TAG_WM,
726 "Attempted to freeze screen with non-existing app token: " + mContainer);
727 return;
728 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800729 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800730 }
731 }
732
733 public void stopFreezingScreen(boolean force) {
734 synchronized(mWindowMap) {
735 if (mContainer == null) {
736 return;
737 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800738 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
739 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
740 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800741 }
742 }
743
744 /**
745 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
746 * In portrait mode, it grabs the full screenshot.
747 *
748 * @param displayId the Display to take a screenshot of.
749 * @param width the width of the target bitmap
750 * @param height the height of the target bitmap
751 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
752 */
753 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
754 try {
755 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
756 final DisplayContent dc;
757 synchronized(mWindowMap) {
758 dc = mRoot.getDisplayContentOrCreate(displayId);
759 if (dc == null) {
760 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
761 + ": returning null. No Display for displayId=" + displayId);
762 return null;
763 }
764 }
765 return dc.screenshotApplications(mToken.asBinder(), width, height,
766 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100767 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800768 } finally {
769 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
770 }
771 }
772
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800773 void reportStartingWindowDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700774 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800775 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800776
777 void reportWindowsDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700778 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800779 }
780
781 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800782 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800783 }
784
785 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800786 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800787 }
788
789 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700790 boolean keyDispatchingTimedOut(String reason, int windowPid) {
791 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800792 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800793
794 @Override
795 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700796 return "AppWindowContainerController{"
797 + " token=" + mToken
798 + " mContainer=" + mContainer
799 + " mListener=" + mListener
800 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800801 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800802}