blob: c982f081d624408d530c8f3bf4048d19d2312c02 [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;
21import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
Jorim Jaggie4b0f282017-05-17 15:10:29 +020022import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080023import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
24import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
29import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
30import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080031
Jorim Jaggie2c77f92016-12-29 14:57:22 +010032import android.app.ActivityManager.TaskSnapshot;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080033import android.content.res.CompatibilityInfo;
34import android.content.res.Configuration;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080035import android.graphics.Bitmap;
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -070036import android.graphics.Rect;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080037import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080038import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080039import android.os.IBinder;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080040import android.os.Trace;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080041import android.util.Slog;
42import android.view.IApplicationToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080043import android.view.WindowManagerPolicy.StartingSurface;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080044
Winson Chung30480042017-01-26 10:55:34 -080045import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080046import com.android.server.AttributeCache;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080047/**
48 * Controller for the app window token container. This is created by activity manager to link
49 * activity records to the app window token container they use in window manager.
50 *
51 * Test class: {@link AppWindowContainerControllerTests}
52 */
53public class AppWindowContainerController
54 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
55
Jorim Jaggi02886a82016-12-06 09:10:06 -080056 private static final int STARTING_WINDOW_TYPE_NONE = 0;
57 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
58 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
59
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080060 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010061 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080062
Jorim Jaggi3878ca32017-02-02 17:13:05 -080063 private final Runnable mOnStartingWindowDrawn = () -> {
64 if (mListener == null) {
65 return;
66 }
67 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
68 + AppWindowContainerController.this.mToken);
69 mListener.onStartingWindowDrawn();
70 };
71
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080072 private final Runnable mOnWindowsDrawn = () -> {
73 if (mListener == null) {
74 return;
75 }
76 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
77 + AppWindowContainerController.this.mToken);
78 mListener.onWindowsDrawn();
79 };
80
81 private final Runnable mOnWindowsVisible = () -> {
82 if (mListener == null) {
83 return;
84 }
85 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
86 + AppWindowContainerController.this.mToken);
87 mListener.onWindowsVisible();
88 };
89
90 private final Runnable mOnWindowsGone = () -> {
91 if (mListener == null) {
92 return;
93 }
94 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
95 + AppWindowContainerController.this.mToken);
96 mListener.onWindowsGone();
97 };
98
Jorim Jaggi02886a82016-12-06 09:10:06 -080099 private final Runnable mRemoveStartingWindow = () -> {
100 StartingSurface surface = null;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800101 synchronized (mWindowMap) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200102 if (mContainer == null) {
103 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
104 + " remove starting window");
105 return;
106 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800107 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
108 + ": startingWindow=" + mContainer.startingWindow
109 + " startingView=" + mContainer.startingSurface);
110 if (mContainer.startingWindow != null) {
111 surface = mContainer.startingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800112 mContainer.startingData = null;
113 mContainer.startingSurface = null;
114 mContainer.startingWindow = null;
115 mContainer.startingDisplayed = false;
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200116 if (surface == null && DEBUG_STARTING_WINDOW) {
117 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
118 + "remove");
119 }
120 } else if (DEBUG_STARTING_WINDOW) {
121 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
122 + mContainer);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800123 }
124 }
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100125 if (surface != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800126 try {
127 surface.remove();
128 } catch (Exception e) {
129 Slog.w(TAG_WM, "Exception when removing starting window", e);
130 }
131 }
132 };
133
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800134 private final Runnable mAddStartingWindow = () -> {
135 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100136 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800137
138 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100139 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200140 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
141 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100142 return;
143 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800144 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100145 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800146 }
147
148 if (startingData == null) {
149 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200150 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
151 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800152 return;
153 }
154
155 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100156 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800157
Jorim Jaggi02886a82016-12-06 09:10:06 -0800158 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800159 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100160 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800161 } catch (Exception e) {
162 Slog.w(TAG_WM, "Exception when adding starting window", e);
163 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800164 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800165 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800166 synchronized(mWindowMap) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100167 if (container.removed || container.startingData == null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800168 // If the window was successfully added, then
169 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100170 if (container.startingWindow != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800171 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100172 "Aborted starting " + container
173 + ": removed=" + container.removed
174 + " startingData=" + container.startingData);
175 container.startingWindow = null;
176 container.startingData = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800177 abort = true;
178 }
179 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100180 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800181 }
182 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
183 "Added starting " + mContainer
184 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100185 + container.startingWindow + " startingView="
186 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800187 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800188 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100189 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800190 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200191 } else if (DEBUG_STARTING_WINDOW) {
192 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800193 }
194 };
195
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800196 public AppWindowContainerController(TaskWindowContainerController taskController,
197 IApplicationToken token, AppWindowContainerListener listener, int index,
198 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800199 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700200 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
201 Configuration overrideConfig, Rect bounds) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800202 this(taskController, token, listener, index, requestedOrientation, fullscreen,
203 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800204 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
205 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700206 WindowManagerService.getInstance(), overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800207 }
208
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800209 public AppWindowContainerController(TaskWindowContainerController taskController,
210 IApplicationToken token, AppWindowContainerListener listener, int index,
211 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800212 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
213 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700214 WindowManagerService service, Configuration overrideConfig, Rect bounds) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800215 super(listener, service);
Jorim Jaggi9bafc712017-01-19 17:28:30 +0100216 mHandler = new Handler(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800217 mToken = token;
218 synchronized(mWindowMap) {
219 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
220 if (atoken != null) {
221 // TODO: Should this throw an exception instead?
222 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
223 return;
224 }
225
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800226 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800227 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800228 throw new IllegalArgumentException("AppWindowContainerController: invalid "
229 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800230 }
231
Winson Chung30480042017-01-26 10:55:34 -0800232 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800233 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
234 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700235 alwaysFocusable, this, overrideConfig, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800236 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800237 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800238 task.addChild(atoken, index);
239 }
240 }
241
Winson Chung30480042017-01-26 10:55:34 -0800242 @VisibleForTesting
243 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
244 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
245 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
246 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700247 boolean alwaysFocusable, AppWindowContainerController controller,
248 Configuration overrideConfig, Rect bounds) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100249 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800250 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
251 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700252 controller, overrideConfig, bounds);
Winson Chung30480042017-01-26 10:55:34 -0800253 }
254
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800255 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800256 synchronized(mWindowMap) {
257 final DisplayContent dc = mRoot.getDisplayContent(displayId);
258 if (dc == null) {
259 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
260 + mToken + " from non-existing displayId=" + displayId);
261 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800262 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800263 dc.removeAppToken(mToken.asBinder());
264 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800265 }
266 }
267
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800268 @Override
269 public void removeContainer() {
270 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800271 }
272
Winson Chung30480042017-01-26 10:55:34 -0800273 public void reparent(TaskWindowContainerController taskController, int position) {
274 synchronized (mWindowMap) {
275 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
276 + " to task=" + taskController + " at " + position);
277 if (mContainer == null) {
278 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
279 "reparent: could not find app token=" + mToken);
280 return;
281 }
282 final Task task = taskController.mContainer;
283 if (task == null) {
284 throw new IllegalArgumentException("reparent: could not find task="
285 + taskController);
286 }
287 mContainer.reparent(task, position);
288 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
289 }
290 }
291
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800292 public Configuration setOrientation(int requestedOrientation, int displayId,
293 Configuration displayConfig, boolean freezeScreenIfNeeded) {
294 synchronized(mWindowMap) {
295 if (mContainer == null) {
296 Slog.w(TAG_WM,
297 "Attempted to set orientation of non-existing app token: " + mToken);
298 return null;
299 }
300
301 mContainer.setOrientation(requestedOrientation);
302
303 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
304 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
305
306 }
307 }
308
309 public int getOrientation() {
310 synchronized(mWindowMap) {
311 if (mContainer == null) {
312 return SCREEN_ORIENTATION_UNSPECIFIED;
313 }
314
315 return mContainer.getOrientationIgnoreVisibility();
316 }
317 }
318
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700319 // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
320 // a generic way to set override config. Need to untangle current ways the override config is
321 // currently set for tasks and displays before we are doing that though.
322 public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
323 synchronized(mWindowMap) {
324 if (mContainer != null) {
325 mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
326 }
327 }
328 }
329
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100330 public void setDisablePreviewScreenshots(boolean disable) {
331 synchronized (mWindowMap) {
332 if (mContainer == null) {
333 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
334 + " token: " + mToken);
335 return;
336 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200337 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100338 }
339 }
340
Wale Ogunwale89973222017-04-23 18:39:45 -0700341 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800342 synchronized(mWindowMap) {
343 if (mContainer == null) {
344 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
345 + mToken);
346 return;
347 }
348
349 final AppWindowToken wtoken = mContainer;
350
351 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
352 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
353 + " hidden=" + wtoken.hidden + " hiddenRequested="
354 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
355
356 mService.mOpeningApps.remove(wtoken);
357 mService.mClosingApps.remove(wtoken);
358 wtoken.waitingToShow = false;
359 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700360 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800361
362 if (!visible) {
363 // If the app is dead while it was visible, we kept its dead window on screen.
364 // Now that the app is going invisible, we can remove it. It will be restarted
365 // if made visible again.
366 wtoken.removeDeadWindows();
367 wtoken.setVisibleBeforeClientHidden();
368 } else {
369 if (!mService.mAppTransition.isTransitionSet()
370 && mService.mAppTransition.isReady()) {
371 // Add the app mOpeningApps if transition is unset but ready. This means
372 // we're doing a screen freeze, and the unfreeze will wait for all opening
373 // apps to be ready.
374 mService.mOpeningApps.add(wtoken);
375 }
376 wtoken.startingMoved = false;
377 // If the token is currently hidden (should be the common case), or has been
378 // stopped, then we need to set up to wait for its windows to be ready.
379 if (wtoken.hidden || wtoken.mAppStopped) {
380 wtoken.clearAllDrawn();
381
382 // If the app was already visible, don't reset the waitingToShow state.
383 if (wtoken.hidden) {
384 wtoken.waitingToShow = true;
385 }
386
Wale Ogunwale89973222017-04-23 18:39:45 -0700387 if (wtoken.isClientHidden()) {
388 // In the case where we are making an app visible but holding off for a
389 // transition, we still need to tell the client to make its windows visible
390 // so they get drawn. Otherwise, we will wait on performing the transition
391 // until all windows have been drawn, they never will be, and we are sad.
392 wtoken.setClientHidden(false);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800393 }
394 }
395 wtoken.requestUpdateWallpaperIfNeeded();
396
397 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
398 wtoken.mAppStopped = false;
399 }
400
401 // If we are preparing an app transition, then delay changing
402 // the visibility of this token until we execute that transition.
403 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
404 // A dummy animation is a placeholder animation which informs others that an
405 // animation is going on (in this case an application transition). If the animation
406 // was transferred from another application/animator, no dummy animator should be
407 // created since an animation is already in progress.
408 if (wtoken.mAppAnimator.usingTransferredAnimation
409 && wtoken.mAppAnimator.animation == null) {
410 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
411 + ", using null transferred animation!");
412 }
413 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
414 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
415 if (DEBUG_APP_TRANSITIONS) Slog.v(
416 TAG_WM, "Setting dummy animation on: " + wtoken);
417 wtoken.mAppAnimator.setDummyAnimation();
418 }
419 wtoken.inPendingTransaction = true;
420 if (visible) {
421 mService.mOpeningApps.add(wtoken);
422 wtoken.mEnteringAnimation = true;
423 } else {
424 mService.mClosingApps.add(wtoken);
425 wtoken.mEnteringAnimation = false;
426 }
427 if (mService.mAppTransition.getAppTransition()
428 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
429 // We're launchingBehind, add the launching activity to mOpeningApps.
430 final WindowState win =
431 mService.getDefaultDisplayContentLocked().findFocusedWindow();
432 if (win != null) {
433 final AppWindowToken focusedToken = win.mAppToken;
434 if (focusedToken != null) {
435 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
436 + " adding " + focusedToken + " to mOpeningApps");
437 // Force animation to be loaded.
438 focusedToken.hidden = true;
439 mService.mOpeningApps.add(focusedToken);
440 }
441 }
442 }
443 return;
444 }
445
446 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
447 wtoken.updateReportedVisibilityLocked();
448 }
449 }
450
451 /**
452 * Notifies that we launched an app that might be visible or not visible depending on what kind
453 * of Keyguard flags it's going to set on its windows.
454 */
455 public void notifyUnknownVisibilityLaunched() {
456 synchronized(mWindowMap) {
457 if (mContainer != null) {
458 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
459 }
460 }
461 }
462
463 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
464 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700465 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi70aa4d12017-05-15 00:05:54 +0200466 boolean allowTaskSnapshot, boolean activityCreated) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800467 synchronized(mWindowMap) {
468 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200469 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
470 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
471 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800472
473 if (mContainer == null) {
474 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
475 return false;
476 }
477
478 // If the display is frozen, we won't do anything until the actual window is
479 // displayed so there is no reason to put in the starting window.
480 if (!mService.okToDisplay()) {
481 return false;
482 }
483
484 if (mContainer.startingData != null) {
485 return false;
486 }
487
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700488 final WindowState mainWin = mContainer.findMainWindow();
489 if (mainWin != null && mainWin.isVisible() && mainWin.isDrawnLw()) {
490 // App already has a visible window that is drawn...why would you want a starting
491 // window?
492 return false;
493 }
494
Jorim Jaggibae01b12017-04-11 16:29:10 -0700495 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi70aa4d12017-05-15 00:05:54 +0200496 allowTaskSnapshot, activityCreated);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800497
498 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
499 return createSnapshot();
500 }
501
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800502 // If this is a translucent window, then don't show a starting window -- the current
503 // effect (a full-screen opaque starting window that fades away to the real contents
504 // when it is ready) does not work for this.
505 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
506 + Integer.toHexString(theme));
507 if (theme != 0) {
508 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
509 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
510 if (ent == null) {
511 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
512 // see that.
513 return false;
514 }
515 final boolean windowIsTranslucent = ent.array.getBoolean(
516 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
517 final boolean windowIsFloating = ent.array.getBoolean(
518 com.android.internal.R.styleable.Window_windowIsFloating, false);
519 final boolean windowShowWallpaper = ent.array.getBoolean(
520 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
521 final boolean windowDisableStarting = ent.array.getBoolean(
522 com.android.internal.R.styleable.Window_windowDisablePreview, false);
523 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
524 + " Floating=" + windowIsFloating
525 + " ShowWallpaper=" + windowShowWallpaper);
526 if (windowIsTranslucent) {
527 return false;
528 }
529 if (windowIsFloating || windowDisableStarting) {
530 return false;
531 }
532 if (windowShowWallpaper) {
533 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
534 == null) {
535 // If this theme is requesting a wallpaper, and the wallpaper
536 // is not currently visible, then this effectively serves as
537 // an opaque window and our starting window transition animation
538 // can still work. We just need to make sure the starting window
539 // is also showing the wallpaper.
540 windowFlags |= FLAG_SHOW_WALLPAPER;
541 } else {
542 return false;
543 }
544 }
545 }
546
547 if (mContainer.transferStartingWindow(transferFrom)) {
548 return true;
549 }
550
Jorim Jaggi02886a82016-12-06 09:10:06 -0800551 // There is no existing starting window, and we don't want to create a splash screen, so
552 // that's it!
553 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800554 return false;
555 }
556
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200557 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100558 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800559 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
560 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800561 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800562 }
563 return true;
564 }
565
Jorim Jaggibae01b12017-04-11 16:29:10 -0700566 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi70aa4d12017-05-15 00:05:54 +0200567 boolean allowTaskSnapshot, boolean activityCreated) {
568 if (newTask || !processRunning
569 || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800570 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700571 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800572 return STARTING_WINDOW_TYPE_SNAPSHOT;
573 } else {
574 return STARTING_WINDOW_TYPE_NONE;
575 }
576 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800577
Jorim Jaggi02886a82016-12-06 09:10:06 -0800578 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800579 // Note: we really want to do sendMessageAtFrontOfQueue() because we
580 // want to process the message ASAP, before any other queued
581 // messages.
582 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100583 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800584 }
585
Jorim Jaggi02886a82016-12-06 09:10:06 -0800586 private boolean createSnapshot() {
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100587 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
Bryce Lee6d410262017-02-28 15:30:17 -0800588 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
Jorim Jaggi35e3f532017-03-17 17:06:50 +0100589 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800590
591 if (snapshot == null) {
592 return false;
593 }
594
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200595 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200596 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800597 scheduleAddStartingWindow();
598 return true;
599 }
600
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800601 public void removeStartingWindow() {
602 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800603 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
604 // Already scheduled.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200605 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Trying to remove starting window but "
606 + "already scheduled");
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800607 return;
608 }
609
610 if (mContainer.startingWindow == null) {
611 if (mContainer.startingData != null) {
612 // Starting window has not been added yet, but it is scheduled to be added.
613 // Go ahead and cancel the request.
614 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
615 "Clearing startingData for token=" + mContainer);
616 mContainer.startingData = null;
617 }
618 return;
619 }
620
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200621 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800622 + " startingWindow=" + mContainer.startingWindow);
623 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800624 }
625 }
626
627 public void pauseKeyDispatching() {
628 synchronized (mWindowMap) {
629 if (mContainer != null) {
630 mService.mInputMonitor.pauseDispatchingLw(mContainer);
631 }
632 }
633 }
634
635 public void resumeKeyDispatching() {
636 synchronized (mWindowMap) {
637 if (mContainer != null) {
638 mService.mInputMonitor.resumeDispatchingLw(mContainer);
639 }
640 }
641 }
642
Jorim Jaggibae01b12017-04-11 16:29:10 -0700643 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800644 synchronized(mWindowMap) {
645 if (mContainer == null) {
646 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
647 return;
648 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700649 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800650 }
651 }
652
653 public void notifyAppStopped() {
654 synchronized(mWindowMap) {
655 if (mContainer == null) {
656 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
657 + mToken);
658 return;
659 }
660 mContainer.notifyAppStopped();
661 }
662 }
663
664 public void startFreezingScreen(int configChanges) {
665 synchronized(mWindowMap) {
666 if (configChanges == 0 && mService.okToDisplay()) {
667 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
668 return;
669 }
670
671 if (mContainer == null) {
672 Slog.w(TAG_WM,
673 "Attempted to freeze screen with non-existing app token: " + mContainer);
674 return;
675 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800676 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800677 }
678 }
679
680 public void stopFreezingScreen(boolean force) {
681 synchronized(mWindowMap) {
682 if (mContainer == null) {
683 return;
684 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800685 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
686 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
687 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800688 }
689 }
690
691 /**
692 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
693 * In portrait mode, it grabs the full screenshot.
694 *
695 * @param displayId the Display to take a screenshot of.
696 * @param width the width of the target bitmap
697 * @param height the height of the target bitmap
698 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
699 */
700 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
701 try {
702 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
703 final DisplayContent dc;
704 synchronized(mWindowMap) {
705 dc = mRoot.getDisplayContentOrCreate(displayId);
706 if (dc == null) {
707 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
708 + ": returning null. No Display for displayId=" + displayId);
709 return null;
710 }
711 }
712 return dc.screenshotApplications(mToken.asBinder(), width, height,
713 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100714 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800715 } finally {
716 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
717 }
718 }
719
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800720 void reportStartingWindowDrawn() {
721 mHandler.post(mOnStartingWindowDrawn);
722 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800723
724 void reportWindowsDrawn() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800725 mHandler.post(mOnWindowsDrawn);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800726 }
727
728 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800729 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800730 }
731
732 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800733 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800734 }
735
736 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700737 boolean keyDispatchingTimedOut(String reason, int windowPid) {
738 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800739 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800740
741 @Override
742 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700743 return "AppWindowContainerController{"
744 + " token=" + mToken
745 + " mContainer=" + mContainer
746 + " mListener=" + mListener
747 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800748 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800749}