blob: 8cfbf68e3b5dfb4cf0cc809057f15b327627cfb6 [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;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080041import android.os.Trace;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080042import android.util.Slog;
43import android.view.IApplicationToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080044import android.view.WindowManagerPolicy.StartingSurface;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080045
Winson Chung30480042017-01-26 10:55:34 -080046import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080047import com.android.server.AttributeCache;
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
Jorim Jaggi3878ca32017-02-02 17:13:05 -080064 private final Runnable mOnStartingWindowDrawn = () -> {
65 if (mListener == null) {
66 return;
67 }
68 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
69 + AppWindowContainerController.this.mToken);
70 mListener.onStartingWindowDrawn();
71 };
72
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080073 private final Runnable mOnWindowsDrawn = () -> {
74 if (mListener == null) {
75 return;
76 }
77 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
78 + AppWindowContainerController.this.mToken);
79 mListener.onWindowsDrawn();
80 };
81
82 private final Runnable mOnWindowsVisible = () -> {
83 if (mListener == null) {
84 return;
85 }
86 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
87 + AppWindowContainerController.this.mToken);
88 mListener.onWindowsVisible();
89 };
90
91 private final Runnable mOnWindowsGone = () -> {
92 if (mListener == null) {
93 return;
94 }
95 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
96 + AppWindowContainerController.this.mToken);
97 mListener.onWindowsGone();
98 };
99
Jorim Jaggi02886a82016-12-06 09:10:06 -0800100 private final Runnable mRemoveStartingWindow = () -> {
101 StartingSurface surface = null;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800102 synchronized (mWindowMap) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200103 if (mContainer == null) {
104 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
105 + " remove starting window");
106 return;
107 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800108 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
109 + ": startingWindow=" + mContainer.startingWindow
110 + " startingView=" + mContainer.startingSurface);
Jorim Jaggicfeff742017-05-23 18:00:48 +0200111 if (mContainer.startingData != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800112 surface = mContainer.startingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800113 mContainer.startingData = null;
114 mContainer.startingSurface = null;
115 mContainer.startingWindow = null;
116 mContainer.startingDisplayed = false;
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200117 if (surface == null && DEBUG_STARTING_WINDOW) {
118 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
119 + "remove");
120 }
121 } else if (DEBUG_STARTING_WINDOW) {
122 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
123 + mContainer);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800124 }
125 }
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100126 if (surface != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800127 try {
128 surface.remove();
129 } catch (Exception e) {
130 Slog.w(TAG_WM, "Exception when removing starting window", e);
131 }
132 }
133 };
134
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800135 private final Runnable mAddStartingWindow = () -> {
136 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100137 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800138
139 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100140 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200141 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
142 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100143 return;
144 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800145 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100146 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800147 }
148
149 if (startingData == null) {
150 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200151 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
152 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800153 return;
154 }
155
156 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100157 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800158
Jorim Jaggi02886a82016-12-06 09:10:06 -0800159 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800160 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100161 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800162 } catch (Exception e) {
163 Slog.w(TAG_WM, "Exception when adding starting window", e);
164 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800165 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800166 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800167 synchronized(mWindowMap) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200168 // If the window was successfully added, then
169 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100170 if (container.removed || container.startingData == null) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200171 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
172 "Aborted starting " + container
173 + ": removed=" + container.removed
174 + " startingData=" + container.startingData);
175 container.startingWindow = null;
176 container.startingData = null;
177 abort = true;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800178 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100179 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800180 }
181 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
182 "Added starting " + mContainer
183 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100184 + container.startingWindow + " startingView="
185 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800186 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800187 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100188 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800189 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200190 } else if (DEBUG_STARTING_WINDOW) {
191 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800192 }
193 };
194
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800195 public AppWindowContainerController(TaskWindowContainerController taskController,
196 IApplicationToken token, AppWindowContainerListener listener, int index,
197 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800198 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700199 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
200 Configuration overrideConfig, Rect bounds) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800201 this(taskController, token, listener, index, requestedOrientation, fullscreen,
202 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800203 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
204 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700205 WindowManagerService.getInstance(), overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800206 }
207
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800208 public AppWindowContainerController(TaskWindowContainerController taskController,
209 IApplicationToken token, AppWindowContainerListener listener, int index,
210 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800211 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
212 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700213 WindowManagerService service, Configuration overrideConfig, Rect bounds) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800214 super(listener, service);
Jorim Jaggi9bafc712017-01-19 17:28:30 +0100215 mHandler = new Handler(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800216 mToken = token;
217 synchronized(mWindowMap) {
218 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
219 if (atoken != null) {
220 // TODO: Should this throw an exception instead?
221 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
222 return;
223 }
224
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800225 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800226 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800227 throw new IllegalArgumentException("AppWindowContainerController: invalid "
228 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800229 }
230
Winson Chung30480042017-01-26 10:55:34 -0800231 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800232 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
233 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700234 alwaysFocusable, this, overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800235 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800236 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800237 task.addChild(atoken, index);
238 }
239 }
240
Winson Chung30480042017-01-26 10:55:34 -0800241 @VisibleForTesting
242 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
243 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
244 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
245 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700246 boolean alwaysFocusable, AppWindowContainerController controller,
247 Configuration overrideConfig, Rect bounds) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100248 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800249 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
250 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700251 controller, overrideConfig, bounds);
Winson Chung30480042017-01-26 10:55:34 -0800252 }
253
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800254 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800255 synchronized(mWindowMap) {
256 final DisplayContent dc = mRoot.getDisplayContent(displayId);
257 if (dc == null) {
258 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
259 + mToken + " from non-existing displayId=" + displayId);
260 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800261 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800262 dc.removeAppToken(mToken.asBinder());
263 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800264 }
265 }
266
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800267 @Override
268 public void removeContainer() {
269 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800270 }
271
Winson Chung30480042017-01-26 10:55:34 -0800272 public void reparent(TaskWindowContainerController taskController, int position) {
273 synchronized (mWindowMap) {
274 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
275 + " to task=" + taskController + " at " + position);
276 if (mContainer == null) {
277 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
278 "reparent: could not find app token=" + mToken);
279 return;
280 }
281 final Task task = taskController.mContainer;
282 if (task == null) {
283 throw new IllegalArgumentException("reparent: could not find task="
284 + taskController);
285 }
286 mContainer.reparent(task, position);
287 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
288 }
289 }
290
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800291 public Configuration setOrientation(int requestedOrientation, int displayId,
292 Configuration displayConfig, boolean freezeScreenIfNeeded) {
293 synchronized(mWindowMap) {
294 if (mContainer == null) {
295 Slog.w(TAG_WM,
296 "Attempted to set orientation of non-existing app token: " + mToken);
297 return null;
298 }
299
300 mContainer.setOrientation(requestedOrientation);
301
302 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
303 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
304
305 }
306 }
307
308 public int getOrientation() {
309 synchronized(mWindowMap) {
310 if (mContainer == null) {
311 return SCREEN_ORIENTATION_UNSPECIFIED;
312 }
313
314 return mContainer.getOrientationIgnoreVisibility();
315 }
316 }
317
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700318 // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
319 // a generic way to set override config. Need to untangle current ways the override config is
320 // currently set for tasks and displays before we are doing that though.
321 public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
322 synchronized(mWindowMap) {
323 if (mContainer != null) {
324 mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
325 }
326 }
327 }
328
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100329 public void setDisablePreviewScreenshots(boolean disable) {
330 synchronized (mWindowMap) {
331 if (mContainer == null) {
332 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
333 + " token: " + mToken);
334 return;
335 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200336 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100337 }
338 }
339
Wale Ogunwale89973222017-04-23 18:39:45 -0700340 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800341 synchronized(mWindowMap) {
342 if (mContainer == null) {
343 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
344 + mToken);
345 return;
346 }
347
348 final AppWindowToken wtoken = mContainer;
349
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700350 // Don't set visibility to false if we were already not visible. This prevents WM from
351 // adding the app to the closing app list which doesn't make sense for something that is
352 // already not visible. However, set visibility to true even if we are already visible.
353 // This makes sure the app is added to the opening apps list so that the right
354 // transition can be selected.
355 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
356 // concept of setting visibility...
357 if (!visible && wtoken.hiddenRequested) {
358
359 if (!deferHidingClient && wtoken.mDeferHidingClient) {
360 // We previously deferred telling the client to hide itself when visibility was
361 // initially set to false. Now we would like it to hide, so go ahead and set it.
362 wtoken.mDeferHidingClient = deferHidingClient;
363 wtoken.setClientHidden(true);
364 }
365 return;
366 }
367
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800368 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
369 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
370 + " hidden=" + wtoken.hidden + " hiddenRequested="
371 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
372
373 mService.mOpeningApps.remove(wtoken);
374 mService.mClosingApps.remove(wtoken);
375 wtoken.waitingToShow = false;
376 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700377 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800378
379 if (!visible) {
380 // If the app is dead while it was visible, we kept its dead window on screen.
381 // Now that the app is going invisible, we can remove it. It will be restarted
382 // if made visible again.
383 wtoken.removeDeadWindows();
384 wtoken.setVisibleBeforeClientHidden();
Jorim Jaggi45ca0542017-05-30 16:16:01 -0700385 mService.mUnknownAppVisibilityController.appRemovedOrHidden(wtoken);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800386 } else {
387 if (!mService.mAppTransition.isTransitionSet()
388 && mService.mAppTransition.isReady()) {
389 // Add the app mOpeningApps if transition is unset but ready. This means
390 // we're doing a screen freeze, and the unfreeze will wait for all opening
391 // apps to be ready.
392 mService.mOpeningApps.add(wtoken);
393 }
394 wtoken.startingMoved = false;
395 // If the token is currently hidden (should be the common case), or has been
396 // stopped, then we need to set up to wait for its windows to be ready.
397 if (wtoken.hidden || wtoken.mAppStopped) {
398 wtoken.clearAllDrawn();
399
400 // If the app was already visible, don't reset the waitingToShow state.
401 if (wtoken.hidden) {
402 wtoken.waitingToShow = true;
403 }
404
Wale Ogunwale89973222017-04-23 18:39:45 -0700405 if (wtoken.isClientHidden()) {
406 // In the case where we are making an app visible but holding off for a
407 // transition, we still need to tell the client to make its windows visible
408 // so they get drawn. Otherwise, we will wait on performing the transition
409 // until all windows have been drawn, they never will be, and we are sad.
410 wtoken.setClientHidden(false);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800411 }
412 }
413 wtoken.requestUpdateWallpaperIfNeeded();
414
415 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
416 wtoken.mAppStopped = false;
417 }
418
419 // If we are preparing an app transition, then delay changing
420 // the visibility of this token until we execute that transition.
421 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
422 // A dummy animation is a placeholder animation which informs others that an
423 // animation is going on (in this case an application transition). If the animation
424 // was transferred from another application/animator, no dummy animator should be
425 // created since an animation is already in progress.
426 if (wtoken.mAppAnimator.usingTransferredAnimation
427 && wtoken.mAppAnimator.animation == null) {
428 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
429 + ", using null transferred animation!");
430 }
431 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
432 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
433 if (DEBUG_APP_TRANSITIONS) Slog.v(
434 TAG_WM, "Setting dummy animation on: " + wtoken);
435 wtoken.mAppAnimator.setDummyAnimation();
436 }
437 wtoken.inPendingTransaction = true;
438 if (visible) {
439 mService.mOpeningApps.add(wtoken);
440 wtoken.mEnteringAnimation = true;
441 } else {
442 mService.mClosingApps.add(wtoken);
443 wtoken.mEnteringAnimation = false;
444 }
445 if (mService.mAppTransition.getAppTransition()
446 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
447 // We're launchingBehind, add the launching activity to mOpeningApps.
448 final WindowState win =
449 mService.getDefaultDisplayContentLocked().findFocusedWindow();
450 if (win != null) {
451 final AppWindowToken focusedToken = win.mAppToken;
452 if (focusedToken != null) {
453 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
454 + " adding " + focusedToken + " to mOpeningApps");
455 // Force animation to be loaded.
456 focusedToken.hidden = true;
457 mService.mOpeningApps.add(focusedToken);
458 }
459 }
460 }
461 return;
462 }
463
464 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
465 wtoken.updateReportedVisibilityLocked();
466 }
467 }
468
469 /**
470 * Notifies that we launched an app that might be visible or not visible depending on what kind
471 * of Keyguard flags it's going to set on its windows.
472 */
473 public void notifyUnknownVisibilityLaunched() {
474 synchronized(mWindowMap) {
475 if (mContainer != null) {
476 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
477 }
478 }
479 }
480
481 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
482 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700483 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi70aa4d12017-05-15 00:05:54 +0200484 boolean allowTaskSnapshot, boolean activityCreated) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800485 synchronized(mWindowMap) {
486 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200487 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
488 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
489 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800490
491 if (mContainer == null) {
492 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
493 return false;
494 }
495
496 // If the display is frozen, we won't do anything until the actual window is
497 // displayed so there is no reason to put in the starting window.
498 if (!mService.okToDisplay()) {
499 return false;
500 }
501
502 if (mContainer.startingData != null) {
503 return false;
504 }
505
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700506 final WindowState mainWin = mContainer.findMainWindow();
507 if (mainWin != null && mainWin.isVisible() && mainWin.isDrawnLw()) {
508 // App already has a visible window that is drawn...why would you want a starting
509 // window?
510 return false;
511 }
512
Jorim Jaggibae01b12017-04-11 16:29:10 -0700513 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi70aa4d12017-05-15 00:05:54 +0200514 allowTaskSnapshot, activityCreated);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800515
516 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
517 return createSnapshot();
518 }
519
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800520 // If this is a translucent window, then don't show a starting window -- the current
521 // effect (a full-screen opaque starting window that fades away to the real contents
522 // when it is ready) does not work for this.
523 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
524 + Integer.toHexString(theme));
525 if (theme != 0) {
526 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
527 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
528 if (ent == null) {
529 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
530 // see that.
531 return false;
532 }
533 final boolean windowIsTranslucent = ent.array.getBoolean(
534 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
535 final boolean windowIsFloating = ent.array.getBoolean(
536 com.android.internal.R.styleable.Window_windowIsFloating, false);
537 final boolean windowShowWallpaper = ent.array.getBoolean(
538 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
539 final boolean windowDisableStarting = ent.array.getBoolean(
540 com.android.internal.R.styleable.Window_windowDisablePreview, false);
541 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
542 + " Floating=" + windowIsFloating
543 + " ShowWallpaper=" + windowShowWallpaper);
544 if (windowIsTranslucent) {
545 return false;
546 }
547 if (windowIsFloating || windowDisableStarting) {
548 return false;
549 }
550 if (windowShowWallpaper) {
551 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
552 == null) {
553 // If this theme is requesting a wallpaper, and the wallpaper
554 // is not currently visible, then this effectively serves as
555 // an opaque window and our starting window transition animation
556 // can still work. We just need to make sure the starting window
557 // is also showing the wallpaper.
558 windowFlags |= FLAG_SHOW_WALLPAPER;
559 } else {
560 return false;
561 }
562 }
563 }
564
565 if (mContainer.transferStartingWindow(transferFrom)) {
566 return true;
567 }
568
Jorim Jaggi02886a82016-12-06 09:10:06 -0800569 // There is no existing starting window, and we don't want to create a splash screen, so
570 // that's it!
571 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800572 return false;
573 }
574
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200575 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100576 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800577 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
578 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800579 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800580 }
581 return true;
582 }
583
Jorim Jaggibae01b12017-04-11 16:29:10 -0700584 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi70aa4d12017-05-15 00:05:54 +0200585 boolean allowTaskSnapshot, boolean activityCreated) {
Matthew Ng606dd802017-06-05 14:06:32 -0700586 if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
587 // TODO(b/34099271): Remove this statement to add back the starting window and figure
588 // out why it causes flickering, the starting window appears over the thumbnail while
589 // the docked from recents transition occurs
590 return STARTING_WINDOW_TYPE_NONE;
591 } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800592 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700593 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800594 return STARTING_WINDOW_TYPE_SNAPSHOT;
595 } else {
596 return STARTING_WINDOW_TYPE_NONE;
597 }
598 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800599
Jorim Jaggi02886a82016-12-06 09:10:06 -0800600 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800601 // Note: we really want to do sendMessageAtFrontOfQueue() because we
602 // want to process the message ASAP, before any other queued
603 // messages.
604 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100605 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800606 }
607
Jorim Jaggi02886a82016-12-06 09:10:06 -0800608 private boolean createSnapshot() {
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100609 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
Bryce Lee6d410262017-02-28 15:30:17 -0800610 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
Jorim Jaggi35e3f532017-03-17 17:06:50 +0100611 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800612
613 if (snapshot == null) {
614 return false;
615 }
616
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200617 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200618 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800619 scheduleAddStartingWindow();
620 return true;
621 }
622
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800623 public void removeStartingWindow() {
624 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800625 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
626 // Already scheduled.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200627 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Trying to remove starting window but "
628 + "already scheduled");
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800629 return;
630 }
631
632 if (mContainer.startingWindow == null) {
633 if (mContainer.startingData != null) {
634 // Starting window has not been added yet, but it is scheduled to be added.
635 // Go ahead and cancel the request.
636 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
637 "Clearing startingData for token=" + mContainer);
638 mContainer.startingData = null;
639 }
640 return;
641 }
642
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200643 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800644 + " startingWindow=" + mContainer.startingWindow);
645 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800646 }
647 }
648
649 public void pauseKeyDispatching() {
650 synchronized (mWindowMap) {
651 if (mContainer != null) {
652 mService.mInputMonitor.pauseDispatchingLw(mContainer);
653 }
654 }
655 }
656
657 public void resumeKeyDispatching() {
658 synchronized (mWindowMap) {
659 if (mContainer != null) {
660 mService.mInputMonitor.resumeDispatchingLw(mContainer);
661 }
662 }
663 }
664
Jorim Jaggibae01b12017-04-11 16:29:10 -0700665 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800666 synchronized(mWindowMap) {
667 if (mContainer == null) {
668 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
669 return;
670 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700671 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800672 }
673 }
674
675 public void notifyAppStopped() {
676 synchronized(mWindowMap) {
677 if (mContainer == null) {
678 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
679 + mToken);
680 return;
681 }
682 mContainer.notifyAppStopped();
683 }
684 }
685
686 public void startFreezingScreen(int configChanges) {
687 synchronized(mWindowMap) {
688 if (configChanges == 0 && mService.okToDisplay()) {
689 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
690 return;
691 }
692
693 if (mContainer == null) {
694 Slog.w(TAG_WM,
695 "Attempted to freeze screen with non-existing app token: " + mContainer);
696 return;
697 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800698 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800699 }
700 }
701
702 public void stopFreezingScreen(boolean force) {
703 synchronized(mWindowMap) {
704 if (mContainer == null) {
705 return;
706 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800707 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
708 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
709 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800710 }
711 }
712
713 /**
714 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
715 * In portrait mode, it grabs the full screenshot.
716 *
717 * @param displayId the Display to take a screenshot of.
718 * @param width the width of the target bitmap
719 * @param height the height of the target bitmap
720 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
721 */
722 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
723 try {
724 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
725 final DisplayContent dc;
726 synchronized(mWindowMap) {
727 dc = mRoot.getDisplayContentOrCreate(displayId);
728 if (dc == null) {
729 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
730 + ": returning null. No Display for displayId=" + displayId);
731 return null;
732 }
733 }
734 return dc.screenshotApplications(mToken.asBinder(), width, height,
735 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100736 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800737 } finally {
738 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
739 }
740 }
741
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800742 void reportStartingWindowDrawn() {
743 mHandler.post(mOnStartingWindowDrawn);
744 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800745
746 void reportWindowsDrawn() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800747 mHandler.post(mOnWindowsDrawn);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800748 }
749
750 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800751 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800752 }
753
754 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800755 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800756 }
757
758 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700759 boolean keyDispatchingTimedOut(String reason, int windowPid) {
760 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800761 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800762
763 @Override
764 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700765 return "AppWindowContainerController{"
766 + " token=" + mToken
767 + " mContainer=" + mContainer
768 + " mListener=" + mListener
769 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800770 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800771}