blob: 1ca98ac77e1c860d6134d9d583774c0adff3fe04 [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;
David Stevensf62360c2017-03-16 19:00:20 -070020import static android.view.Display.DEFAULT_DISPLAY;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080021import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
Matthew Ng606dd802017-06-05 14:06:32 -070022
23import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080024import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
29import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
30import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
31import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
32import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080033
Jorim Jaggie2c77f92016-12-29 14:57:22 +010034import android.app.ActivityManager.TaskSnapshot;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080035import android.content.res.CompatibilityInfo;
36import android.content.res.Configuration;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080037import android.graphics.Bitmap;
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -070038import android.graphics.Rect;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080039import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080040import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080041import android.os.IBinder;
Sudheer Shankac766db02017-06-12 10:37:29 -070042import android.os.Looper;
43import android.os.Message;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080044import android.os.Trace;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080045import android.util.Slog;
Jorim Jaggi42befc62017-06-13 11:54:04 -070046import android.view.DisplayInfo;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080047import android.view.IApplicationToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080048import android.view.WindowManagerPolicy.StartingSurface;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080049
Winson Chung30480042017-01-26 10:55:34 -080050import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080051import com.android.server.AttributeCache;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080052/**
53 * Controller for the app window token container. This is created by activity manager to link
54 * activity records to the app window token container they use in window manager.
55 *
56 * Test class: {@link AppWindowContainerControllerTests}
57 */
58public class AppWindowContainerController
59 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
60
Jorim Jaggi02886a82016-12-06 09:10:06 -080061 private static final int STARTING_WINDOW_TYPE_NONE = 0;
62 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
63 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
64
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080065 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010066 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080067
Sudheer Shankac766db02017-06-12 10:37:29 -070068 private final class H extends Handler {
69 public static final int NOTIFY_WINDOWS_DRAWN = 1;
70 public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080071
Sudheer Shankac766db02017-06-12 10:37:29 -070072 public H(Looper looper) {
73 super(looper);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080074 }
Sudheer Shankac766db02017-06-12 10:37:29 -070075
76 @Override
77 public void handleMessage(Message msg) {
78 switch (msg.what) {
79 case NOTIFY_WINDOWS_DRAWN:
80 if (mListener == null) {
81 return;
82 }
83 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
84 + AppWindowContainerController.this.mToken);
85 mListener.onWindowsDrawn(msg.getWhen());
86 break;
87 case NOTIFY_STARTING_WINDOW_DRAWN:
88 if (mListener == null) {
89 return;
90 }
91 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
92 + AppWindowContainerController.this.mToken);
93 mListener.onStartingWindowDrawn(msg.getWhen());
94 break;
95 default:
96 break;
97 }
98 }
99 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800100
101 private final Runnable mOnWindowsVisible = () -> {
102 if (mListener == null) {
103 return;
104 }
105 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
106 + AppWindowContainerController.this.mToken);
107 mListener.onWindowsVisible();
108 };
109
110 private final Runnable mOnWindowsGone = () -> {
111 if (mListener == null) {
112 return;
113 }
114 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
115 + AppWindowContainerController.this.mToken);
116 mListener.onWindowsGone();
117 };
118
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800119 private final Runnable mAddStartingWindow = () -> {
120 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100121 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800122
123 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100124 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200125 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
126 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100127 return;
128 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800129 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100130 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800131 }
132
133 if (startingData == null) {
134 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200135 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
136 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800137 return;
138 }
139
140 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100141 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800142
Jorim Jaggi02886a82016-12-06 09:10:06 -0800143 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800144 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100145 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800146 } catch (Exception e) {
147 Slog.w(TAG_WM, "Exception when adding starting window", e);
148 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800149 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800150 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800151 synchronized(mWindowMap) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200152 // If the window was successfully added, then
153 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100154 if (container.removed || container.startingData == null) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200155 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
156 "Aborted starting " + container
157 + ": removed=" + container.removed
158 + " startingData=" + container.startingData);
159 container.startingWindow = null;
160 container.startingData = null;
161 abort = true;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800162 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100163 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800164 }
165 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
166 "Added starting " + mContainer
167 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100168 + container.startingWindow + " startingView="
169 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800170 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800171 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100172 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800173 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200174 } else if (DEBUG_STARTING_WINDOW) {
175 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800176 }
177 };
178
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800179 public AppWindowContainerController(TaskWindowContainerController taskController,
180 IApplicationToken token, AppWindowContainerListener listener, int index,
181 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800182 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700183 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
184 Configuration overrideConfig, Rect bounds) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800185 this(taskController, token, listener, index, requestedOrientation, fullscreen,
186 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800187 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
188 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700189 WindowManagerService.getInstance(), overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800190 }
191
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800192 public AppWindowContainerController(TaskWindowContainerController taskController,
193 IApplicationToken token, AppWindowContainerListener listener, int index,
194 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800195 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
196 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700197 WindowManagerService service, Configuration overrideConfig, Rect bounds) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800198 super(listener, service);
Sudheer Shankac766db02017-06-12 10:37:29 -0700199 mHandler = new H(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800200 mToken = token;
201 synchronized(mWindowMap) {
202 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
203 if (atoken != null) {
204 // TODO: Should this throw an exception instead?
205 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
206 return;
207 }
208
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800209 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800210 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800211 throw new IllegalArgumentException("AppWindowContainerController: invalid "
212 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800213 }
214
Winson Chung30480042017-01-26 10:55:34 -0800215 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800216 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
217 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700218 alwaysFocusable, this, overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800219 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800220 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800221 task.addChild(atoken, index);
222 }
223 }
224
Winson Chung30480042017-01-26 10:55:34 -0800225 @VisibleForTesting
226 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
227 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
228 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
229 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700230 boolean alwaysFocusable, AppWindowContainerController controller,
231 Configuration overrideConfig, Rect bounds) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100232 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800233 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
234 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700235 controller, overrideConfig, bounds);
Winson Chung30480042017-01-26 10:55:34 -0800236 }
237
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800238 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800239 synchronized(mWindowMap) {
240 final DisplayContent dc = mRoot.getDisplayContent(displayId);
241 if (dc == null) {
242 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
243 + mToken + " from non-existing displayId=" + displayId);
244 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800245 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800246 dc.removeAppToken(mToken.asBinder());
247 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800248 }
249 }
250
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800251 @Override
252 public void removeContainer() {
253 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800254 }
255
Winson Chung30480042017-01-26 10:55:34 -0800256 public void reparent(TaskWindowContainerController taskController, int position) {
257 synchronized (mWindowMap) {
258 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
259 + " to task=" + taskController + " at " + position);
260 if (mContainer == null) {
261 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
262 "reparent: could not find app token=" + mToken);
263 return;
264 }
265 final Task task = taskController.mContainer;
266 if (task == null) {
267 throw new IllegalArgumentException("reparent: could not find task="
268 + taskController);
269 }
270 mContainer.reparent(task, position);
271 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
272 }
273 }
274
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800275 public Configuration setOrientation(int requestedOrientation, int displayId,
276 Configuration displayConfig, boolean freezeScreenIfNeeded) {
277 synchronized(mWindowMap) {
278 if (mContainer == null) {
279 Slog.w(TAG_WM,
280 "Attempted to set orientation of non-existing app token: " + mToken);
281 return null;
282 }
283
284 mContainer.setOrientation(requestedOrientation);
285
286 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
287 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
288
289 }
290 }
291
292 public int getOrientation() {
293 synchronized(mWindowMap) {
294 if (mContainer == null) {
295 return SCREEN_ORIENTATION_UNSPECIFIED;
296 }
297
298 return mContainer.getOrientationIgnoreVisibility();
299 }
300 }
301
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700302 // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
303 // a generic way to set override config. Need to untangle current ways the override config is
304 // currently set for tasks and displays before we are doing that though.
305 public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
306 synchronized(mWindowMap) {
307 if (mContainer != null) {
308 mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
309 }
310 }
311 }
312
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100313 public void setDisablePreviewScreenshots(boolean disable) {
314 synchronized (mWindowMap) {
315 if (mContainer == null) {
316 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
317 + " token: " + mToken);
318 return;
319 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200320 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100321 }
322 }
323
Wale Ogunwale89973222017-04-23 18:39:45 -0700324 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800325 synchronized(mWindowMap) {
326 if (mContainer == null) {
327 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
328 + mToken);
329 return;
330 }
331
332 final AppWindowToken wtoken = mContainer;
333
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700334 // Don't set visibility to false if we were already not visible. This prevents WM from
335 // adding the app to the closing app list which doesn't make sense for something that is
336 // already not visible. However, set visibility to true even if we are already visible.
337 // This makes sure the app is added to the opening apps list so that the right
338 // transition can be selected.
339 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
340 // concept of setting visibility...
341 if (!visible && wtoken.hiddenRequested) {
342
343 if (!deferHidingClient && wtoken.mDeferHidingClient) {
344 // We previously deferred telling the client to hide itself when visibility was
345 // initially set to false. Now we would like it to hide, so go ahead and set it.
346 wtoken.mDeferHidingClient = deferHidingClient;
347 wtoken.setClientHidden(true);
348 }
349 return;
350 }
351
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800352 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
353 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
354 + " hidden=" + wtoken.hidden + " hiddenRequested="
355 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
356
357 mService.mOpeningApps.remove(wtoken);
358 mService.mClosingApps.remove(wtoken);
359 wtoken.waitingToShow = false;
360 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700361 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800362
363 if (!visible) {
364 // If the app is dead while it was visible, we kept its dead window on screen.
365 // Now that the app is going invisible, we can remove it. It will be restarted
366 // if made visible again.
367 wtoken.removeDeadWindows();
368 wtoken.setVisibleBeforeClientHidden();
Jorim Jaggi45ca0542017-05-30 16:16:01 -0700369 mService.mUnknownAppVisibilityController.appRemovedOrHidden(wtoken);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800370 } else {
371 if (!mService.mAppTransition.isTransitionSet()
372 && mService.mAppTransition.isReady()) {
373 // Add the app mOpeningApps if transition is unset but ready. This means
374 // we're doing a screen freeze, and the unfreeze will wait for all opening
375 // apps to be ready.
376 mService.mOpeningApps.add(wtoken);
377 }
378 wtoken.startingMoved = false;
379 // If the token is currently hidden (should be the common case), or has been
380 // stopped, then we need to set up to wait for its windows to be ready.
381 if (wtoken.hidden || wtoken.mAppStopped) {
382 wtoken.clearAllDrawn();
383
384 // If the app was already visible, don't reset the waitingToShow state.
385 if (wtoken.hidden) {
386 wtoken.waitingToShow = true;
387 }
388
Wale Ogunwale89973222017-04-23 18:39:45 -0700389 if (wtoken.isClientHidden()) {
390 // In the case where we are making an app visible but holding off for a
391 // transition, we still need to tell the client to make its windows visible
392 // so they get drawn. Otherwise, we will wait on performing the transition
393 // until all windows have been drawn, they never will be, and we are sad.
394 wtoken.setClientHidden(false);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800395 }
396 }
397 wtoken.requestUpdateWallpaperIfNeeded();
398
399 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
400 wtoken.mAppStopped = false;
401 }
402
403 // If we are preparing an app transition, then delay changing
404 // the visibility of this token until we execute that transition.
David Stevensf62360c2017-03-16 19:00:20 -0700405 if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800406 // A dummy animation is a placeholder animation which informs others that an
407 // animation is going on (in this case an application transition). If the animation
408 // was transferred from another application/animator, no dummy animator should be
409 // created since an animation is already in progress.
410 if (wtoken.mAppAnimator.usingTransferredAnimation
411 && wtoken.mAppAnimator.animation == null) {
412 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
413 + ", using null transferred animation!");
414 }
415 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
416 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
417 if (DEBUG_APP_TRANSITIONS) Slog.v(
418 TAG_WM, "Setting dummy animation on: " + wtoken);
419 wtoken.mAppAnimator.setDummyAnimation();
420 }
421 wtoken.inPendingTransaction = true;
422 if (visible) {
423 mService.mOpeningApps.add(wtoken);
424 wtoken.mEnteringAnimation = true;
425 } else {
426 mService.mClosingApps.add(wtoken);
427 wtoken.mEnteringAnimation = false;
428 }
429 if (mService.mAppTransition.getAppTransition()
430 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
431 // We're launchingBehind, add the launching activity to mOpeningApps.
432 final WindowState win =
433 mService.getDefaultDisplayContentLocked().findFocusedWindow();
434 if (win != null) {
435 final AppWindowToken focusedToken = win.mAppToken;
436 if (focusedToken != null) {
437 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
438 + " adding " + focusedToken + " to mOpeningApps");
439 // Force animation to be loaded.
440 focusedToken.hidden = true;
441 mService.mOpeningApps.add(focusedToken);
442 }
443 }
444 }
445 return;
446 }
447
448 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
449 wtoken.updateReportedVisibilityLocked();
450 }
451 }
452
453 /**
454 * Notifies that we launched an app that might be visible or not visible depending on what kind
455 * of Keyguard flags it's going to set on its windows.
456 */
457 public void notifyUnknownVisibilityLaunched() {
458 synchronized(mWindowMap) {
459 if (mContainer != null) {
460 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
461 }
462 }
463 }
464
465 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
466 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700467 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700468 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800469 synchronized(mWindowMap) {
470 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200471 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
472 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
473 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800474
475 if (mContainer == null) {
476 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
477 return false;
478 }
479
480 // If the display is frozen, we won't do anything until the actual window is
481 // displayed so there is no reason to put in the starting window.
David Stevensf62360c2017-03-16 19:00:20 -0700482 if (!mContainer.okToDisplay()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800483 return false;
484 }
485
486 if (mContainer.startingData != null) {
487 return false;
488 }
489
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700490 final WindowState mainWin = mContainer.findMainWindow();
Jorim Jaggie6b1b3b2017-07-24 16:44:18 +0200491 if (mainWin != null && mainWin.mWinAnimator.getShown()) {
492 // App already has a visible window...why would you want a starting window?
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700493 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
Jorim Jaggi19be6052017-08-03 18:33:43 +0200615 public void removeStartingWindow() {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800616 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800617 if (mContainer.startingWindow == null) {
618 if (mContainer.startingData != null) {
619 // Starting window has not been added yet, but it is scheduled to be added.
620 // Go ahead and cancel the request.
621 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
622 "Clearing startingData for token=" + mContainer);
623 mContainer.startingData = null;
624 }
625 return;
626 }
627
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700628 final StartingSurface surface;
629 if (mContainer.startingData != null) {
630 surface = mContainer.startingSurface;
631 mContainer.startingData = null;
632 mContainer.startingSurface = null;
633 mContainer.startingWindow = null;
634 mContainer.startingDisplayed = false;
635 if (surface == null && DEBUG_STARTING_WINDOW) {
636 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
637 + "remove");
638 }
639 } else {
640 if (DEBUG_STARTING_WINDOW) {
641 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
642 + mContainer);
643 }
644 return;
645 }
646
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200647 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700648 + " startingWindow=" + mContainer.startingWindow
649 + " startingView=" + mContainer.startingSurface);
Jorim Jaggia3382192017-07-18 14:33:21 +0200650
651 // Use the same thread to remove the window as we used to add it, as otherwise we end up
652 // with things in the view hierarchy being called from different threads.
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700653 mHandler.post(() -> {
654 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
655 try {
656 surface.remove();
657 } catch (Exception e) {
658 Slog.w(TAG_WM, "Exception when removing starting window", e);
659 }
660 });
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800661 }
662 }
663
664 public void pauseKeyDispatching() {
665 synchronized (mWindowMap) {
666 if (mContainer != null) {
667 mService.mInputMonitor.pauseDispatchingLw(mContainer);
668 }
669 }
670 }
671
672 public void resumeKeyDispatching() {
673 synchronized (mWindowMap) {
674 if (mContainer != null) {
675 mService.mInputMonitor.resumeDispatchingLw(mContainer);
676 }
677 }
678 }
679
Jorim Jaggibae01b12017-04-11 16:29:10 -0700680 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800681 synchronized(mWindowMap) {
682 if (mContainer == null) {
683 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
684 return;
685 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700686 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800687 }
688 }
689
690 public void notifyAppStopped() {
691 synchronized(mWindowMap) {
692 if (mContainer == null) {
693 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
694 + mToken);
695 return;
696 }
697 mContainer.notifyAppStopped();
698 }
699 }
700
701 public void startFreezingScreen(int configChanges) {
702 synchronized(mWindowMap) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800703 if (mContainer == null) {
704 Slog.w(TAG_WM,
705 "Attempted to freeze screen with non-existing app token: " + mContainer);
706 return;
707 }
David Stevensf62360c2017-03-16 19:00:20 -0700708
709 if (configChanges == 0 && mContainer.okToDisplay()) {
710 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
711 return;
712 }
713
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800714 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800715 }
716 }
717
718 public void stopFreezingScreen(boolean force) {
719 synchronized(mWindowMap) {
720 if (mContainer == null) {
721 return;
722 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800723 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
724 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
725 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800726 }
727 }
728
729 /**
730 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
731 * In portrait mode, it grabs the full screenshot.
732 *
733 * @param displayId the Display to take a screenshot of.
734 * @param width the width of the target bitmap
735 * @param height the height of the target bitmap
736 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
737 */
738 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
739 try {
740 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
741 final DisplayContent dc;
742 synchronized(mWindowMap) {
743 dc = mRoot.getDisplayContentOrCreate(displayId);
744 if (dc == null) {
745 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
746 + ": returning null. No Display for displayId=" + displayId);
747 return null;
748 }
749 }
750 return dc.screenshotApplications(mToken.asBinder(), width, height,
751 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100752 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800753 } finally {
754 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
755 }
756 }
757
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800758 void reportStartingWindowDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700759 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800760 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800761
762 void reportWindowsDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700763 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800764 }
765
766 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800767 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800768 }
769
770 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800771 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800772 }
773
774 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700775 boolean keyDispatchingTimedOut(String reason, int windowPid) {
776 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800777 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800778
779 @Override
780 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700781 return "AppWindowContainerController{"
782 + " token=" + mToken
783 + " mContainer=" + mContainer
784 + " mListener=" + mListener
785 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800786 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800787}