blob: a528ecdf537ead1af6b6a7703484efe468e6b0e9 [file] [log] [blame]
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
19import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
David Stevensf62360c2017-03-16 19:00:20 -070020import static android.view.Display.DEFAULT_DISPLAY;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080021import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
Matthew Ng606dd802017-06-05 14:06:32 -070022
23import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080024import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
29import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
30import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
31import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
32import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080033
Jorim Jaggie2c77f92016-12-29 14:57:22 +010034import android.app.ActivityManager.TaskSnapshot;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080035import android.content.res.CompatibilityInfo;
36import android.content.res.Configuration;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080037import android.graphics.Bitmap;
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -070038import android.graphics.Rect;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080039import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080040import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080041import android.os.IBinder;
Sudheer Shankac766db02017-06-12 10:37:29 -070042import android.os.Looper;
43import android.os.Message;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080044import android.os.Trace;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080045import android.util.Slog;
Jorim Jaggi42befc62017-06-13 11:54:04 -070046import android.view.DisplayInfo;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080047import android.view.IApplicationToken;
48
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;
Adrian Roose99bc052017-11-20 17:55:31 +010051import com.android.server.policy.WindowManagerPolicy.StartingSurface;
52
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080053/**
54 * Controller for the app window token container. This is created by activity manager to link
55 * activity records to the app window token container they use in window manager.
56 *
57 * Test class: {@link AppWindowContainerControllerTests}
58 */
59public class AppWindowContainerController
60 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
61
Jorim Jaggi02886a82016-12-06 09:10:06 -080062 private static final int STARTING_WINDOW_TYPE_NONE = 0;
63 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
64 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
65
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080066 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010067 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080068
Sudheer Shankac766db02017-06-12 10:37:29 -070069 private final class H extends Handler {
70 public static final int NOTIFY_WINDOWS_DRAWN = 1;
71 public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080072
Sudheer Shankac766db02017-06-12 10:37:29 -070073 public H(Looper looper) {
74 super(looper);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080075 }
Sudheer Shankac766db02017-06-12 10:37:29 -070076
77 @Override
78 public void handleMessage(Message msg) {
79 switch (msg.what) {
80 case NOTIFY_WINDOWS_DRAWN:
81 if (mListener == null) {
82 return;
83 }
84 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
85 + AppWindowContainerController.this.mToken);
86 mListener.onWindowsDrawn(msg.getWhen());
87 break;
88 case NOTIFY_STARTING_WINDOW_DRAWN:
89 if (mListener == null) {
90 return;
91 }
92 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
93 + AppWindowContainerController.this.mToken);
94 mListener.onStartingWindowDrawn(msg.getWhen());
95 break;
96 default:
97 break;
98 }
99 }
100 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800101
102 private final Runnable mOnWindowsVisible = () -> {
103 if (mListener == null) {
104 return;
105 }
106 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
107 + AppWindowContainerController.this.mToken);
108 mListener.onWindowsVisible();
109 };
110
111 private final Runnable mOnWindowsGone = () -> {
112 if (mListener == null) {
113 return;
114 }
115 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
116 + AppWindowContainerController.this.mToken);
117 mListener.onWindowsGone();
118 };
119
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800120 private final Runnable mAddStartingWindow = () -> {
121 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100122 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800123
124 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100125 if (mContainer == null) {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200126 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
127 + " add starting window");
Jorim Jaggi73f88202017-01-12 13:54:40 +0100128 return;
129 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800130 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100131 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800132 }
133
134 if (startingData == null) {
135 // Animation has been canceled... do nothing.
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200136 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "startingData was nulled out before handling"
137 + " mAddStartingWindow: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800138 return;
139 }
140
141 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100142 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800143
Jorim Jaggi02886a82016-12-06 09:10:06 -0800144 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800145 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100146 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800147 } catch (Exception e) {
148 Slog.w(TAG_WM, "Exception when adding starting window", e);
149 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800150 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800151 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800152 synchronized(mWindowMap) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200153 // If the window was successfully added, then
154 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100155 if (container.removed || container.startingData == null) {
Jorim Jaggicfeff742017-05-23 18:00:48 +0200156 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
157 "Aborted starting " + container
158 + ": removed=" + container.removed
159 + " startingData=" + container.startingData);
160 container.startingWindow = null;
161 container.startingData = null;
162 abort = true;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800163 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100164 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800165 }
166 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
167 "Added starting " + mContainer
168 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100169 + container.startingWindow + " startingView="
170 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800171 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800172 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100173 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800174 }
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200175 } else if (DEBUG_STARTING_WINDOW) {
176 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800177 }
178 };
179
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800180 public AppWindowContainerController(TaskWindowContainerController taskController,
181 IApplicationToken token, AppWindowContainerListener listener, int index,
182 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800183 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700184 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700185 Rect bounds) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800186 this(taskController, token, listener, index, requestedOrientation, fullscreen,
187 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800188 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
189 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700190 WindowManagerService.getInstance(), bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800191 }
192
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800193 public AppWindowContainerController(TaskWindowContainerController taskController,
194 IApplicationToken token, AppWindowContainerListener listener, int index,
195 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800196 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
197 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700198 WindowManagerService service, Rect bounds) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800199 super(listener, service);
Sudheer Shankac766db02017-06-12 10:37:29 -0700200 mHandler = new H(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800201 mToken = token;
202 synchronized(mWindowMap) {
203 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
204 if (atoken != null) {
205 // TODO: Should this throw an exception instead?
206 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
207 return;
208 }
209
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800210 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800211 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800212 throw new IllegalArgumentException("AppWindowContainerController: invalid "
213 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800214 }
215
Winson Chung30480042017-01-26 10:55:34 -0800216 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800217 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
218 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700219 alwaysFocusable, this, bounds);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800220 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800221 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800222 task.addChild(atoken, index);
223 }
224 }
225
Winson Chung30480042017-01-26 10:55:34 -0800226 @VisibleForTesting
227 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
228 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
229 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
230 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700231 boolean alwaysFocusable, AppWindowContainerController controller, Rect bounds) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100232 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800233 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
234 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Wale Ogunwale034a8ec2017-09-02 17:14:40 -0700235 controller, bounds);
Winson Chung30480042017-01-26 10:55:34 -0800236 }
237
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800238 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800239 synchronized(mWindowMap) {
240 final DisplayContent dc = mRoot.getDisplayContent(displayId);
241 if (dc == null) {
242 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
243 + mToken + " from non-existing displayId=" + displayId);
244 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800245 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800246 dc.removeAppToken(mToken.asBinder());
247 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800248 }
249 }
250
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800251 @Override
252 public void removeContainer() {
253 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800254 }
255
Winson Chung30480042017-01-26 10:55:34 -0800256 public void reparent(TaskWindowContainerController taskController, int position) {
257 synchronized (mWindowMap) {
258 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
259 + " to task=" + taskController + " at " + position);
260 if (mContainer == null) {
261 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
262 "reparent: could not find app token=" + mToken);
263 return;
264 }
265 final Task task = taskController.mContainer;
266 if (task == null) {
267 throw new IllegalArgumentException("reparent: could not find task="
268 + taskController);
269 }
270 mContainer.reparent(task, position);
271 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
272 }
273 }
274
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800275 public Configuration setOrientation(int requestedOrientation, int displayId,
276 Configuration displayConfig, boolean freezeScreenIfNeeded) {
277 synchronized(mWindowMap) {
278 if (mContainer == null) {
279 Slog.w(TAG_WM,
280 "Attempted to set orientation of non-existing app token: " + mToken);
281 return null;
282 }
283
284 mContainer.setOrientation(requestedOrientation);
285
286 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
287 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
288
289 }
290 }
291
292 public int getOrientation() {
293 synchronized(mWindowMap) {
294 if (mContainer == null) {
295 return SCREEN_ORIENTATION_UNSPECIFIED;
296 }
297
298 return mContainer.getOrientationIgnoreVisibility();
299 }
300 }
301
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700302 // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
303 // a generic way to set override config. Need to untangle current ways the override config is
304 // currently set for tasks and displays before we are doing that though.
305 public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
306 synchronized(mWindowMap) {
307 if (mContainer != null) {
308 mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
309 }
310 }
311 }
312
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100313 public void setDisablePreviewScreenshots(boolean disable) {
314 synchronized (mWindowMap) {
315 if (mContainer == null) {
316 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
317 + " token: " + mToken);
318 return;
319 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200320 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100321 }
322 }
323
Tim Murray68ed8442017-08-29 23:21:27 +0000324 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800325 synchronized(mWindowMap) {
326 if (mContainer == null) {
327 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
328 + mToken);
329 return;
330 }
331
332 final AppWindowToken wtoken = mContainer;
333
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700334 // Don't set visibility to false if we were already not visible. This prevents WM from
335 // adding the app to the closing app list which doesn't make sense for something that is
336 // already not visible. However, set visibility to true even if we are already visible.
337 // This makes sure the app is added to the opening apps list so that the right
338 // transition can be selected.
339 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
340 // concept of setting visibility...
341 if (!visible && wtoken.hiddenRequested) {
342
343 if (!deferHidingClient && wtoken.mDeferHidingClient) {
344 // We previously deferred telling the client to hide itself when visibility was
345 // initially set to false. Now we would like it to hide, so go ahead and set it.
346 wtoken.mDeferHidingClient = deferHidingClient;
347 wtoken.setClientHidden(true);
348 }
349 return;
350 }
351
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800352 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
353 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
354 + " hidden=" + wtoken.hidden + " hiddenRequested="
355 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
356
357 mService.mOpeningApps.remove(wtoken);
358 mService.mClosingApps.remove(wtoken);
359 wtoken.waitingToShow = false;
360 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700361 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800362
363 if (!visible) {
364 // If the app is dead while it was visible, we kept its dead window on screen.
365 // Now that the app is going invisible, we can remove it. It will be restarted
366 // if made visible again.
367 wtoken.removeDeadWindows();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800368 } 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.
David Stevensf62360c2017-03-16 19:00:20 -0700403 if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800404 // 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 Jaggi42befc62017-06-13 11:54:04 -0700466 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
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.
David Stevensf62360c2017-03-16 19:00:20 -0700480 if (!mContainer.okToDisplay()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800481 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();
Jorim Jaggie6b1b3b2017-07-24 16:44:18 +0200489 if (mainWin != null && mainWin.mWinAnimator.getShown()) {
490 // App already has a visible window...why would you want a starting window?
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700491 return false;
492 }
493
Jorim Jaggi42befc62017-06-13 11:54:04 -0700494 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
495 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
496 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggibae01b12017-04-11 16:29:10 -0700497 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700498 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800499
500 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700501 return createSnapshot(snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800502 }
503
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800504 // If this is a translucent window, then don't show a starting window -- the current
505 // effect (a full-screen opaque starting window that fades away to the real contents
506 // when it is ready) does not work for this.
507 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
508 + Integer.toHexString(theme));
509 if (theme != 0) {
510 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
511 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
512 if (ent == null) {
513 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
514 // see that.
515 return false;
516 }
517 final boolean windowIsTranslucent = ent.array.getBoolean(
518 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
519 final boolean windowIsFloating = ent.array.getBoolean(
520 com.android.internal.R.styleable.Window_windowIsFloating, false);
521 final boolean windowShowWallpaper = ent.array.getBoolean(
522 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
523 final boolean windowDisableStarting = ent.array.getBoolean(
524 com.android.internal.R.styleable.Window_windowDisablePreview, false);
525 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
526 + " Floating=" + windowIsFloating
527 + " ShowWallpaper=" + windowShowWallpaper);
528 if (windowIsTranslucent) {
529 return false;
530 }
531 if (windowIsFloating || windowDisableStarting) {
532 return false;
533 }
534 if (windowShowWallpaper) {
535 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
536 == null) {
537 // If this theme is requesting a wallpaper, and the wallpaper
538 // is not currently visible, then this effectively serves as
539 // an opaque window and our starting window transition animation
540 // can still work. We just need to make sure the starting window
541 // is also showing the wallpaper.
542 windowFlags |= FLAG_SHOW_WALLPAPER;
543 } else {
544 return false;
545 }
546 }
547 }
548
549 if (mContainer.transferStartingWindow(transferFrom)) {
550 return true;
551 }
552
Jorim Jaggi02886a82016-12-06 09:10:06 -0800553 // There is no existing starting window, and we don't want to create a splash screen, so
554 // that's it!
555 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800556 return false;
557 }
558
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200559 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100560 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800561 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
562 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800563 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800564 }
565 return true;
566 }
567
Jorim Jaggibae01b12017-04-11 16:29:10 -0700568 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700569 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
570 TaskSnapshot snapshot) {
Matthew Ng606dd802017-06-05 14:06:32 -0700571 if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
572 // TODO(b/34099271): Remove this statement to add back the starting window and figure
573 // out why it causes flickering, the starting window appears over the thumbnail while
574 // the docked from recents transition occurs
575 return STARTING_WINDOW_TYPE_NONE;
576 } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800577 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700578 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700579 return snapshot == null ? STARTING_WINDOW_TYPE_NONE
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400580 : snapshotOrientationSameAsTask(snapshot) || fromRecents
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700581 ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800582 } else {
583 return STARTING_WINDOW_TYPE_NONE;
584 }
585 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800586
Jorim Jaggi02886a82016-12-06 09:10:06 -0800587 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800588 // Note: we really want to do sendMessageAtFrontOfQueue() because we
589 // want to process the message ASAP, before any other queued
590 // messages.
591 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100592 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800593 }
594
Jorim Jaggi42befc62017-06-13 11:54:04 -0700595 private boolean createSnapshot(TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800596 if (snapshot == null) {
597 return false;
598 }
599
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200600 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200601 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800602 scheduleAddStartingWindow();
603 return true;
604 }
605
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400606 private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700607 if (snapshot == null) {
608 return false;
609 }
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400610 return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
Jorim Jaggi42befc62017-06-13 11:54:04 -0700611 }
612
Jorim Jaggi19be6052017-08-03 18:33:43 +0200613 public void removeStartingWindow() {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800614 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800615 if (mContainer.startingWindow == null) {
616 if (mContainer.startingData != null) {
617 // Starting window has not been added yet, but it is scheduled to be added.
618 // Go ahead and cancel the request.
619 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
620 "Clearing startingData for token=" + mContainer);
621 mContainer.startingData = null;
622 }
623 return;
624 }
625
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700626 final StartingSurface surface;
627 if (mContainer.startingData != null) {
628 surface = mContainer.startingSurface;
629 mContainer.startingData = null;
630 mContainer.startingSurface = null;
631 mContainer.startingWindow = null;
632 mContainer.startingDisplayed = false;
Seigo Nonakaeafe7372017-08-16 12:39:49 -0700633 if (surface == null) {
634 if (DEBUG_STARTING_WINDOW) {
635 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
636 + "remove");
637 }
638 return;
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700639 }
640 } else {
641 if (DEBUG_STARTING_WINDOW) {
642 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
643 + mContainer);
644 }
645 return;
646 }
647
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200648 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700649 + " startingWindow=" + mContainer.startingWindow
650 + " startingView=" + mContainer.startingSurface);
Jorim Jaggia3382192017-07-18 14:33:21 +0200651
652 // Use the same thread to remove the window as we used to add it, as otherwise we end up
653 // with things in the view hierarchy being called from different threads.
Jorim Jaggi8829cf12017-09-05 12:28:52 +0200654 mService.mAnimationHandler.post(() -> {
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700655 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
656 try {
657 surface.remove();
658 } catch (Exception e) {
659 Slog.w(TAG_WM, "Exception when removing starting window", e);
660 }
661 });
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800662 }
663 }
664
665 public void pauseKeyDispatching() {
666 synchronized (mWindowMap) {
667 if (mContainer != null) {
668 mService.mInputMonitor.pauseDispatchingLw(mContainer);
669 }
670 }
671 }
672
673 public void resumeKeyDispatching() {
674 synchronized (mWindowMap) {
675 if (mContainer != null) {
676 mService.mInputMonitor.resumeDispatchingLw(mContainer);
677 }
678 }
679 }
680
Jorim Jaggibae01b12017-04-11 16:29:10 -0700681 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800682 synchronized(mWindowMap) {
683 if (mContainer == null) {
684 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
685 return;
686 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700687 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800688 }
689 }
690
691 public void notifyAppStopped() {
692 synchronized(mWindowMap) {
693 if (mContainer == null) {
694 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
695 + mToken);
696 return;
697 }
698 mContainer.notifyAppStopped();
699 }
700 }
701
702 public void startFreezingScreen(int configChanges) {
703 synchronized(mWindowMap) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800704 if (mContainer == null) {
705 Slog.w(TAG_WM,
706 "Attempted to freeze screen with non-existing app token: " + mContainer);
707 return;
708 }
David Stevensf62360c2017-03-16 19:00:20 -0700709
710 if (configChanges == 0 && mContainer.okToDisplay()) {
711 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
712 return;
713 }
714
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800715 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800716 }
717 }
718
719 public void stopFreezingScreen(boolean force) {
720 synchronized(mWindowMap) {
721 if (mContainer == null) {
722 return;
723 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800724 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
725 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
726 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800727 }
728 }
729
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800730 void reportStartingWindowDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700731 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800732 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800733
734 void reportWindowsDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700735 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800736 }
737
738 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800739 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800740 }
741
742 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800743 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800744 }
745
746 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700747 boolean keyDispatchingTimedOut(String reason, int windowPid) {
748 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800749 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800750
751 @Override
752 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700753 return "AppWindowContainerController{"
754 + " token=" + mToken
755 + " mContainer=" + mContainer
756 + " mListener=" + mListener
757 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800758 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800759}