blob: 4e4398ee9d91e0a774a1720761e2f0f8d081c223 [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 Jaggi02886a82016-12-06 09:10:06 -0800118 private final Runnable mRemoveStartingWindow = () -> {
119 StartingSurface surface = null;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800120 synchronized (mWindowMap) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200121 if (mContainer == null) {
122 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
123 + " remove starting window");
124 return;
125 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800126 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
127 + ": startingWindow=" + mContainer.startingWindow
128 + " startingView=" + mContainer.startingSurface);
Jorim Jaggicfeff742017-05-23 18:00:48 +0200129 if (mContainer.startingData != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800130 surface = mContainer.startingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800131 mContainer.startingData = null;
132 mContainer.startingSurface = null;
133 mContainer.startingWindow = null;
134 mContainer.startingDisplayed = false;
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200135 if (surface == null && DEBUG_STARTING_WINDOW) {
136 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
137 + "remove");
138 }
139 } else if (DEBUG_STARTING_WINDOW) {
140 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
141 + mContainer);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800142 }
143 }
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100144 if (surface != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800145 try {
146 surface.remove();
147 } catch (Exception e) {
148 Slog.w(TAG_WM, "Exception when removing starting window", e);
149 }
150 }
151 };
152
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800153 private final Runnable mAddStartingWindow = () -> {
154 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100155 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800156
157 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100158 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200159 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
160 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100161 return;
162 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800163 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100164 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800165 }
166
167 if (startingData == null) {
168 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200169 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
170 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800171 return;
172 }
173
174 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100175 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800176
Jorim Jaggi02886a82016-12-06 09:10:06 -0800177 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800178 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100179 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800180 } catch (Exception e) {
181 Slog.w(TAG_WM, "Exception when adding starting window", e);
182 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800183 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800184 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800185 synchronized(mWindowMap) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200186 // If the window was successfully added, then
187 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100188 if (container.removed || container.startingData == null) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200189 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
190 "Aborted starting " + container
191 + ": removed=" + container.removed
192 + " startingData=" + container.startingData);
193 container.startingWindow = null;
194 container.startingData = null;
195 abort = true;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800196 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100197 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800198 }
199 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
200 "Added starting " + mContainer
201 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100202 + container.startingWindow + " startingView="
203 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800204 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800205 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100206 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800207 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200208 } else if (DEBUG_STARTING_WINDOW) {
209 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800210 }
211 };
212
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800213 public AppWindowContainerController(TaskWindowContainerController taskController,
214 IApplicationToken token, AppWindowContainerListener listener, int index,
215 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800216 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700217 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
218 Configuration overrideConfig, Rect bounds) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800219 this(taskController, token, listener, index, requestedOrientation, fullscreen,
220 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800221 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
222 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700223 WindowManagerService.getInstance(), overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800224 }
225
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800226 public AppWindowContainerController(TaskWindowContainerController taskController,
227 IApplicationToken token, AppWindowContainerListener listener, int index,
228 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800229 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
230 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700231 WindowManagerService service, Configuration overrideConfig, Rect bounds) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800232 super(listener, service);
Sudheer Shankac766db02017-06-12 10:37:29 -0700233 mHandler = new H(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800234 mToken = token;
235 synchronized(mWindowMap) {
236 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
237 if (atoken != null) {
238 // TODO: Should this throw an exception instead?
239 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
240 return;
241 }
242
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800243 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800244 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800245 throw new IllegalArgumentException("AppWindowContainerController: invalid "
246 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800247 }
248
Winson Chung30480042017-01-26 10:55:34 -0800249 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800250 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
251 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700252 alwaysFocusable, this, overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800253 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800254 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800255 task.addChild(atoken, index);
256 }
257 }
258
Winson Chung30480042017-01-26 10:55:34 -0800259 @VisibleForTesting
260 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
261 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
262 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
263 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700264 boolean alwaysFocusable, AppWindowContainerController controller,
265 Configuration overrideConfig, Rect bounds) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100266 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800267 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
268 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700269 controller, overrideConfig, bounds);
Winson Chung30480042017-01-26 10:55:34 -0800270 }
271
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800272 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800273 synchronized(mWindowMap) {
274 final DisplayContent dc = mRoot.getDisplayContent(displayId);
275 if (dc == null) {
276 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
277 + mToken + " from non-existing displayId=" + displayId);
278 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800279 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800280 dc.removeAppToken(mToken.asBinder());
281 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800282 }
283 }
284
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800285 @Override
286 public void removeContainer() {
287 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800288 }
289
Winson Chung30480042017-01-26 10:55:34 -0800290 public void reparent(TaskWindowContainerController taskController, int position) {
291 synchronized (mWindowMap) {
292 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
293 + " to task=" + taskController + " at " + position);
294 if (mContainer == null) {
295 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
296 "reparent: could not find app token=" + mToken);
297 return;
298 }
299 final Task task = taskController.mContainer;
300 if (task == null) {
301 throw new IllegalArgumentException("reparent: could not find task="
302 + taskController);
303 }
304 mContainer.reparent(task, position);
305 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
306 }
307 }
308
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800309 public Configuration setOrientation(int requestedOrientation, int displayId,
310 Configuration displayConfig, boolean freezeScreenIfNeeded) {
311 synchronized(mWindowMap) {
312 if (mContainer == null) {
313 Slog.w(TAG_WM,
314 "Attempted to set orientation of non-existing app token: " + mToken);
315 return null;
316 }
317
318 mContainer.setOrientation(requestedOrientation);
319
320 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
321 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
322
323 }
324 }
325
326 public int getOrientation() {
327 synchronized(mWindowMap) {
328 if (mContainer == null) {
329 return SCREEN_ORIENTATION_UNSPECIFIED;
330 }
331
332 return mContainer.getOrientationIgnoreVisibility();
333 }
334 }
335
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700336 // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
337 // a generic way to set override config. Need to untangle current ways the override config is
338 // currently set for tasks and displays before we are doing that though.
339 public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
340 synchronized(mWindowMap) {
341 if (mContainer != null) {
342 mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
343 }
344 }
345 }
346
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100347 public void setDisablePreviewScreenshots(boolean disable) {
348 synchronized (mWindowMap) {
349 if (mContainer == null) {
350 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
351 + " token: " + mToken);
352 return;
353 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200354 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100355 }
356 }
357
Wale Ogunwale89973222017-04-23 18:39:45 -0700358 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800359 synchronized(mWindowMap) {
360 if (mContainer == null) {
361 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
362 + mToken);
363 return;
364 }
365
366 final AppWindowToken wtoken = mContainer;
367
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700368 // Don't set visibility to false if we were already not visible. This prevents WM from
369 // adding the app to the closing app list which doesn't make sense for something that is
370 // already not visible. However, set visibility to true even if we are already visible.
371 // This makes sure the app is added to the opening apps list so that the right
372 // transition can be selected.
373 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
374 // concept of setting visibility...
375 if (!visible && wtoken.hiddenRequested) {
376
377 if (!deferHidingClient && wtoken.mDeferHidingClient) {
378 // We previously deferred telling the client to hide itself when visibility was
379 // initially set to false. Now we would like it to hide, so go ahead and set it.
380 wtoken.mDeferHidingClient = deferHidingClient;
381 wtoken.setClientHidden(true);
382 }
383 return;
384 }
385
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800386 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
387 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
388 + " hidden=" + wtoken.hidden + " hiddenRequested="
389 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
390
391 mService.mOpeningApps.remove(wtoken);
392 mService.mClosingApps.remove(wtoken);
393 wtoken.waitingToShow = false;
394 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700395 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800396
397 if (!visible) {
398 // If the app is dead while it was visible, we kept its dead window on screen.
399 // Now that the app is going invisible, we can remove it. It will be restarted
400 // if made visible again.
401 wtoken.removeDeadWindows();
402 wtoken.setVisibleBeforeClientHidden();
Jorim Jaggi45ca0542017-05-30 16:16:01 -0700403 mService.mUnknownAppVisibilityController.appRemovedOrHidden(wtoken);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800404 } else {
405 if (!mService.mAppTransition.isTransitionSet()
406 && mService.mAppTransition.isReady()) {
407 // Add the app mOpeningApps if transition is unset but ready. This means
408 // we're doing a screen freeze, and the unfreeze will wait for all opening
409 // apps to be ready.
410 mService.mOpeningApps.add(wtoken);
411 }
412 wtoken.startingMoved = false;
413 // If the token is currently hidden (should be the common case), or has been
414 // stopped, then we need to set up to wait for its windows to be ready.
415 if (wtoken.hidden || wtoken.mAppStopped) {
416 wtoken.clearAllDrawn();
417
418 // If the app was already visible, don't reset the waitingToShow state.
419 if (wtoken.hidden) {
420 wtoken.waitingToShow = true;
421 }
422
Wale Ogunwale89973222017-04-23 18:39:45 -0700423 if (wtoken.isClientHidden()) {
424 // In the case where we are making an app visible but holding off for a
425 // transition, we still need to tell the client to make its windows visible
426 // so they get drawn. Otherwise, we will wait on performing the transition
427 // until all windows have been drawn, they never will be, and we are sad.
428 wtoken.setClientHidden(false);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800429 }
430 }
431 wtoken.requestUpdateWallpaperIfNeeded();
432
433 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
434 wtoken.mAppStopped = false;
435 }
436
437 // If we are preparing an app transition, then delay changing
438 // the visibility of this token until we execute that transition.
439 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
440 // A dummy animation is a placeholder animation which informs others that an
441 // animation is going on (in this case an application transition). If the animation
442 // was transferred from another application/animator, no dummy animator should be
443 // created since an animation is already in progress.
444 if (wtoken.mAppAnimator.usingTransferredAnimation
445 && wtoken.mAppAnimator.animation == null) {
446 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
447 + ", using null transferred animation!");
448 }
449 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
450 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
451 if (DEBUG_APP_TRANSITIONS) Slog.v(
452 TAG_WM, "Setting dummy animation on: " + wtoken);
453 wtoken.mAppAnimator.setDummyAnimation();
454 }
455 wtoken.inPendingTransaction = true;
456 if (visible) {
457 mService.mOpeningApps.add(wtoken);
458 wtoken.mEnteringAnimation = true;
459 } else {
460 mService.mClosingApps.add(wtoken);
461 wtoken.mEnteringAnimation = false;
462 }
463 if (mService.mAppTransition.getAppTransition()
464 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
465 // We're launchingBehind, add the launching activity to mOpeningApps.
466 final WindowState win =
467 mService.getDefaultDisplayContentLocked().findFocusedWindow();
468 if (win != null) {
469 final AppWindowToken focusedToken = win.mAppToken;
470 if (focusedToken != null) {
471 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
472 + " adding " + focusedToken + " to mOpeningApps");
473 // Force animation to be loaded.
474 focusedToken.hidden = true;
475 mService.mOpeningApps.add(focusedToken);
476 }
477 }
478 }
479 return;
480 }
481
482 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
483 wtoken.updateReportedVisibilityLocked();
484 }
485 }
486
487 /**
488 * Notifies that we launched an app that might be visible or not visible depending on what kind
489 * of Keyguard flags it's going to set on its windows.
490 */
491 public void notifyUnknownVisibilityLaunched() {
492 synchronized(mWindowMap) {
493 if (mContainer != null) {
494 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
495 }
496 }
497 }
498
499 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
500 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700501 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700502 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800503 synchronized(mWindowMap) {
504 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200505 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
506 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
507 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800508
509 if (mContainer == null) {
510 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
511 return false;
512 }
513
514 // If the display is frozen, we won't do anything until the actual window is
515 // displayed so there is no reason to put in the starting window.
516 if (!mService.okToDisplay()) {
517 return false;
518 }
519
520 if (mContainer.startingData != null) {
521 return false;
522 }
523
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700524 final WindowState mainWin = mContainer.findMainWindow();
525 if (mainWin != null && mainWin.isVisible() && mainWin.isDrawnLw()) {
526 // App already has a visible window that is drawn...why would you want a starting
527 // window?
528 return false;
529 }
530
Jorim Jaggi42befc62017-06-13 11:54:04 -0700531 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
532 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
533 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggibae01b12017-04-11 16:29:10 -0700534 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700535 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800536
537 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700538 return createSnapshot(snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800539 }
540
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800541 // If this is a translucent window, then don't show a starting window -- the current
542 // effect (a full-screen opaque starting window that fades away to the real contents
543 // when it is ready) does not work for this.
544 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
545 + Integer.toHexString(theme));
546 if (theme != 0) {
547 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
548 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
549 if (ent == null) {
550 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
551 // see that.
552 return false;
553 }
554 final boolean windowIsTranslucent = ent.array.getBoolean(
555 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
556 final boolean windowIsFloating = ent.array.getBoolean(
557 com.android.internal.R.styleable.Window_windowIsFloating, false);
558 final boolean windowShowWallpaper = ent.array.getBoolean(
559 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
560 final boolean windowDisableStarting = ent.array.getBoolean(
561 com.android.internal.R.styleable.Window_windowDisablePreview, false);
562 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
563 + " Floating=" + windowIsFloating
564 + " ShowWallpaper=" + windowShowWallpaper);
565 if (windowIsTranslucent) {
566 return false;
567 }
568 if (windowIsFloating || windowDisableStarting) {
569 return false;
570 }
571 if (windowShowWallpaper) {
572 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
573 == null) {
574 // If this theme is requesting a wallpaper, and the wallpaper
575 // is not currently visible, then this effectively serves as
576 // an opaque window and our starting window transition animation
577 // can still work. We just need to make sure the starting window
578 // is also showing the wallpaper.
579 windowFlags |= FLAG_SHOW_WALLPAPER;
580 } else {
581 return false;
582 }
583 }
584 }
585
586 if (mContainer.transferStartingWindow(transferFrom)) {
587 return true;
588 }
589
Jorim Jaggi02886a82016-12-06 09:10:06 -0800590 // There is no existing starting window, and we don't want to create a splash screen, so
591 // that's it!
592 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800593 return false;
594 }
595
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200596 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100597 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800598 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
599 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800600 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800601 }
602 return true;
603 }
604
Jorim Jaggibae01b12017-04-11 16:29:10 -0700605 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700606 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
607 TaskSnapshot snapshot) {
Matthew Ng606dd802017-06-05 14:06:32 -0700608 if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
609 // TODO(b/34099271): Remove this statement to add back the starting window and figure
610 // out why it causes flickering, the starting window appears over the thumbnail while
611 // the docked from recents transition occurs
612 return STARTING_WINDOW_TYPE_NONE;
613 } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800614 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700615 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700616 return snapshot == null ? STARTING_WINDOW_TYPE_NONE
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400617 : snapshotOrientationSameAsTask(snapshot) || fromRecents
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700618 ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800619 } else {
620 return STARTING_WINDOW_TYPE_NONE;
621 }
622 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800623
Jorim Jaggi02886a82016-12-06 09:10:06 -0800624 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800625 // Note: we really want to do sendMessageAtFrontOfQueue() because we
626 // want to process the message ASAP, before any other queued
627 // messages.
628 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100629 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800630 }
631
Jorim Jaggi42befc62017-06-13 11:54:04 -0700632 private boolean createSnapshot(TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800633 if (snapshot == null) {
634 return false;
635 }
636
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200637 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200638 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800639 scheduleAddStartingWindow();
640 return true;
641 }
642
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400643 private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700644 if (snapshot == null) {
645 return false;
646 }
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400647 return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
Jorim Jaggi42befc62017-06-13 11:54:04 -0700648 }
649
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800650 public void removeStartingWindow() {
651 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800652 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
653 // Already scheduled.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200654 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Trying to remove starting window but "
655 + "already scheduled");
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800656 return;
657 }
658
659 if (mContainer.startingWindow == null) {
660 if (mContainer.startingData != null) {
661 // Starting window has not been added yet, but it is scheduled to be added.
662 // Go ahead and cancel the request.
663 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
664 "Clearing startingData for token=" + mContainer);
665 mContainer.startingData = null;
666 }
667 return;
668 }
669
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200670 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800671 + " startingWindow=" + mContainer.startingWindow);
672 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800673 }
674 }
675
676 public void pauseKeyDispatching() {
677 synchronized (mWindowMap) {
678 if (mContainer != null) {
679 mService.mInputMonitor.pauseDispatchingLw(mContainer);
680 }
681 }
682 }
683
684 public void resumeKeyDispatching() {
685 synchronized (mWindowMap) {
686 if (mContainer != null) {
687 mService.mInputMonitor.resumeDispatchingLw(mContainer);
688 }
689 }
690 }
691
Jorim Jaggibae01b12017-04-11 16:29:10 -0700692 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800693 synchronized(mWindowMap) {
694 if (mContainer == null) {
695 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
696 return;
697 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700698 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800699 }
700 }
701
702 public void notifyAppStopped() {
703 synchronized(mWindowMap) {
704 if (mContainer == null) {
705 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
706 + mToken);
707 return;
708 }
709 mContainer.notifyAppStopped();
710 }
711 }
712
713 public void startFreezingScreen(int configChanges) {
714 synchronized(mWindowMap) {
715 if (configChanges == 0 && mService.okToDisplay()) {
716 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
717 return;
718 }
719
720 if (mContainer == null) {
721 Slog.w(TAG_WM,
722 "Attempted to freeze screen with non-existing app token: " + mContainer);
723 return;
724 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800725 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800726 }
727 }
728
729 public void stopFreezingScreen(boolean force) {
730 synchronized(mWindowMap) {
731 if (mContainer == null) {
732 return;
733 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800734 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
735 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
736 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800737 }
738 }
739
740 /**
741 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
742 * In portrait mode, it grabs the full screenshot.
743 *
744 * @param displayId the Display to take a screenshot of.
745 * @param width the width of the target bitmap
746 * @param height the height of the target bitmap
747 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
748 */
749 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
750 try {
751 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
752 final DisplayContent dc;
753 synchronized(mWindowMap) {
754 dc = mRoot.getDisplayContentOrCreate(displayId);
755 if (dc == null) {
756 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
757 + ": returning null. No Display for displayId=" + displayId);
758 return null;
759 }
760 }
761 return dc.screenshotApplications(mToken.asBinder(), width, height,
762 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100763 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800764 } finally {
765 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
766 }
767 }
768
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800769 void reportStartingWindowDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700770 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800771 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800772
773 void reportWindowsDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700774 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800775 }
776
777 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800778 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800779 }
780
781 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800782 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800783 }
784
785 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700786 boolean keyDispatchingTimedOut(String reason, int windowPid) {
787 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800788 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800789
790 @Override
791 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700792 return "AppWindowContainerController{"
793 + " token=" + mToken
794 + " mContainer=" + mContainer
795 + " mListener=" + mListener
796 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800797 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800798}