blob: 644e3c3c732b56acf985e8d52748827084981465 [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
Jorim Jaggif84e2f62018-01-16 14:17:59 +010022import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
23import static android.view.WindowManager.TRANSIT_UNSET;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080024import 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;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080027import 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;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080035import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080036import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080037import android.os.IBinder;
Sudheer Shankac766db02017-06-12 10:37:29 -070038import android.os.Looper;
39import android.os.Message;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080040import android.util.Slog;
41import android.view.IApplicationToken;
Jorim Jaggif84e2f62018-01-16 14:17:59 +010042import android.view.RemoteAnimationDefinition;
43import android.view.WindowManager;
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;
Adrian Roose99bc052017-11-20 17:55:31 +010047import com.android.server.policy.WindowManagerPolicy.StartingSurface;
48
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080049/**
50 * Controller for the app window token container. This is created by activity manager to link
51 * activity records to the app window token container they use in window manager.
52 *
53 * Test class: {@link AppWindowContainerControllerTests}
54 */
55public class AppWindowContainerController
56 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
57
Jorim Jaggi02886a82016-12-06 09:10:06 -080058 private static final int STARTING_WINDOW_TYPE_NONE = 0;
59 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
60 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
61
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080062 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010063 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080064
Sudheer Shankac766db02017-06-12 10:37:29 -070065 private final class H extends Handler {
66 public static final int NOTIFY_WINDOWS_DRAWN = 1;
67 public static final int NOTIFY_STARTING_WINDOW_DRAWN = 2;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080068
Sudheer Shankac766db02017-06-12 10:37:29 -070069 public H(Looper looper) {
70 super(looper);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080071 }
Sudheer Shankac766db02017-06-12 10:37:29 -070072
73 @Override
74 public void handleMessage(Message msg) {
75 switch (msg.what) {
76 case NOTIFY_WINDOWS_DRAWN:
77 if (mListener == null) {
78 return;
79 }
80 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
81 + AppWindowContainerController.this.mToken);
82 mListener.onWindowsDrawn(msg.getWhen());
83 break;
84 case NOTIFY_STARTING_WINDOW_DRAWN:
85 if (mListener == null) {
86 return;
87 }
88 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
89 + AppWindowContainerController.this.mToken);
90 mListener.onStartingWindowDrawn(msg.getWhen());
91 break;
92 default:
93 break;
94 }
95 }
96 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080097
98 private final Runnable mOnWindowsVisible = () -> {
99 if (mListener == null) {
100 return;
101 }
102 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
103 + AppWindowContainerController.this.mToken);
104 mListener.onWindowsVisible();
105 };
106
107 private final Runnable mOnWindowsGone = () -> {
108 if (mListener == null) {
109 return;
110 }
111 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
112 + AppWindowContainerController.this.mToken);
113 mListener.onWindowsGone();
114 };
115
Jorim Jaggid8665f22018-04-10 00:34:24 +0200116 private final Runnable mAddStartingWindow = new Runnable() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800117
Jorim Jaggid8665f22018-04-10 00:34:24 +0200118 @Override
119 public void run() {
120 final StartingData startingData;
121 final AppWindowToken container;
122
123 synchronized (mWindowMap) {
124 if (mContainer == null) {
125 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "mContainer was null while trying to"
126 + " add starting window");
127 return;
128 }
129
130 // There can only be one adding request, silly caller!
131 mService.mAnimationHandler.removeCallbacks(this);
132
133 startingData = mContainer.startingData;
134 container = mContainer;
135 }
136
137 if (startingData == null) {
138 // Animation has been canceled... do nothing.
139 if (DEBUG_STARTING_WINDOW)
140 Slog.v(TAG_WM, "startingData was nulled out before handling"
141 + " mAddStartingWindow: " + mContainer);
Jorim Jaggi73f88202017-01-12 13:54:40 +0100142 return;
143 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800144
Jorim Jaggid8665f22018-04-10 00:34:24 +0200145 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
146 + AppWindowContainerController.this + ": startingData="
147 + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800148
Jorim Jaggid8665f22018-04-10 00:34:24 +0200149 StartingSurface surface = null;
150 try {
151 surface = startingData.createStartingSurface(container);
152 } catch (Exception e) {
153 Slog.w(TAG_WM, "Exception when adding starting window", e);
154 }
155 if (surface != null) {
156 boolean abort = false;
157 synchronized (mWindowMap) {
158 // If the window was successfully added, then
159 // we need to remove it.
160 if (container.removed || container.startingData == null) {
161 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
162 "Aborted starting " + container
163 + ": removed=" + container.removed
164 + " startingData=" + container.startingData);
165 container.startingWindow = null;
166 container.startingData = null;
167 abort = true;
168 } else {
169 container.startingSurface = surface;
170 }
171 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
172 "Added starting " + mContainer
173 + ": startingWindow="
174 + container.startingWindow + " startingView="
175 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800176 }
Jorim Jaggid8665f22018-04-10 00:34:24 +0200177 if (abort) {
178 surface.remove();
179 }
180 } else if (DEBUG_STARTING_WINDOW) {
181 Slog.v(TAG_WM, "Surface returned was null: " + mContainer);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800182 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800183 }
184 };
185
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800186 public AppWindowContainerController(TaskWindowContainerController taskController,
187 IApplicationToken token, AppWindowContainerListener listener, int index,
188 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800189 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
Bryce Leef3c6a472017-11-14 14:53:06 -0800190 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800191 this(taskController, token, listener, index, requestedOrientation, fullscreen,
192 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800193 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
194 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
Bryce Leef3c6a472017-11-14 14:53:06 -0800195 WindowManagerService.getInstance());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800196 }
197
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800198 public AppWindowContainerController(TaskWindowContainerController taskController,
199 IApplicationToken token, AppWindowContainerListener listener, int index,
200 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800201 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
202 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
Bryce Leef3c6a472017-11-14 14:53:06 -0800203 WindowManagerService service) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800204 super(listener, service);
Sudheer Shankac766db02017-06-12 10:37:29 -0700205 mHandler = new H(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800206 mToken = token;
207 synchronized(mWindowMap) {
208 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
209 if (atoken != null) {
210 // TODO: Should this throw an exception instead?
211 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
212 return;
213 }
214
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800215 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800216 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800217 throw new IllegalArgumentException("AppWindowContainerController: invalid "
218 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800219 }
220
Winson Chung30480042017-01-26 10:55:34 -0800221 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800222 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
223 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
Bryce Leef3c6a472017-11-14 14:53:06 -0800224 alwaysFocusable, this);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800225 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800226 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800227 task.addChild(atoken, index);
228 }
229 }
230
Winson Chung30480042017-01-26 10:55:34 -0800231 @VisibleForTesting
232 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
233 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
234 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
235 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
Bryce Leef3c6a472017-11-14 14:53:06 -0800236 boolean alwaysFocusable, AppWindowContainerController controller) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100237 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800238 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
239 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Bryce Leef3c6a472017-11-14 14:53:06 -0800240 controller);
Winson Chung30480042017-01-26 10:55:34 -0800241 }
242
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800243 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800244 synchronized(mWindowMap) {
245 final DisplayContent dc = mRoot.getDisplayContent(displayId);
246 if (dc == null) {
247 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
248 + mToken + " from non-existing displayId=" + displayId);
249 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800250 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800251 dc.removeAppToken(mToken.asBinder());
252 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800253 }
254 }
255
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800256 @Override
257 public void removeContainer() {
258 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800259 }
260
Winson Chung30480042017-01-26 10:55:34 -0800261 public void reparent(TaskWindowContainerController taskController, int position) {
262 synchronized (mWindowMap) {
263 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
264 + " to task=" + taskController + " at " + position);
265 if (mContainer == null) {
266 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
267 "reparent: could not find app token=" + mToken);
268 return;
269 }
270 final Task task = taskController.mContainer;
271 if (task == null) {
272 throw new IllegalArgumentException("reparent: could not find task="
273 + taskController);
274 }
275 mContainer.reparent(task, position);
276 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
277 }
278 }
279
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800280 public Configuration setOrientation(int requestedOrientation, int displayId,
281 Configuration displayConfig, boolean freezeScreenIfNeeded) {
282 synchronized(mWindowMap) {
283 if (mContainer == null) {
284 Slog.w(TAG_WM,
285 "Attempted to set orientation of non-existing app token: " + mToken);
286 return null;
287 }
288
289 mContainer.setOrientation(requestedOrientation);
290
291 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
292 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
293
294 }
295 }
296
297 public int getOrientation() {
298 synchronized(mWindowMap) {
299 if (mContainer == null) {
300 return SCREEN_ORIENTATION_UNSPECIFIED;
301 }
302
303 return mContainer.getOrientationIgnoreVisibility();
304 }
305 }
306
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100307 public void setDisablePreviewScreenshots(boolean disable) {
308 synchronized (mWindowMap) {
309 if (mContainer == null) {
310 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
311 + " token: " + mToken);
312 return;
313 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200314 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100315 }
316 }
317
Tim Murray68ed8442017-08-29 23:21:27 +0000318 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800319 synchronized(mWindowMap) {
320 if (mContainer == null) {
321 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
322 + mToken);
323 return;
324 }
325
326 final AppWindowToken wtoken = mContainer;
327
Wale Ogunwale0c20ee32017-05-23 10:34:48 -0700328 // Don't set visibility to false if we were already not visible. This prevents WM from
329 // adding the app to the closing app list which doesn't make sense for something that is
330 // already not visible. However, set visibility to true even if we are already visible.
331 // This makes sure the app is added to the opening apps list so that the right
332 // transition can be selected.
333 // TODO: Probably a good idea to separate the concept of opening/closing apps from the
334 // concept of setting visibility...
335 if (!visible && wtoken.hiddenRequested) {
336
337 if (!deferHidingClient && wtoken.mDeferHidingClient) {
338 // We previously deferred telling the client to hide itself when visibility was
339 // initially set to false. Now we would like it to hide, so go ahead and set it.
340 wtoken.mDeferHidingClient = deferHidingClient;
341 wtoken.setClientHidden(true);
342 }
343 return;
344 }
345
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800346 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
347 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200348 + " hidden=" + wtoken.isHidden() + " hiddenRequested="
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800349 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
350
351 mService.mOpeningApps.remove(wtoken);
352 mService.mClosingApps.remove(wtoken);
353 wtoken.waitingToShow = false;
354 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700355 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800356
357 if (!visible) {
358 // If the app is dead while it was visible, we kept its dead window on screen.
359 // Now that the app is going invisible, we can remove it. It will be restarted
360 // if made visible again.
361 wtoken.removeDeadWindows();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800362 } else {
363 if (!mService.mAppTransition.isTransitionSet()
364 && mService.mAppTransition.isReady()) {
365 // Add the app mOpeningApps if transition is unset but ready. This means
366 // we're doing a screen freeze, and the unfreeze will wait for all opening
367 // apps to be ready.
368 mService.mOpeningApps.add(wtoken);
369 }
370 wtoken.startingMoved = false;
371 // If the token is currently hidden (should be the common case), or has been
372 // stopped, then we need to set up to wait for its windows to be ready.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200373 if (wtoken.isHidden() || wtoken.mAppStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800374 wtoken.clearAllDrawn();
375
376 // If the app was already visible, don't reset the waitingToShow state.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200377 if (wtoken.isHidden()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800378 wtoken.waitingToShow = true;
379 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800380 }
Jorim Jaggi067b5bf2018-02-23 17:42:39 +0100381
382 // In the case where we are making an app visible but holding off for a transition,
383 // we still need to tell the client to make its windows visible so they get drawn.
384 // Otherwise, we will wait on performing the transition until all windows have been
385 // drawn, they never will be, and we are sad.
386 wtoken.setClientHidden(false);
387
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800388 wtoken.requestUpdateWallpaperIfNeeded();
389
390 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
391 wtoken.mAppStopped = false;
Jorim Jaggi60f9c972018-02-01 19:21:07 +0100392
393 mContainer.transferStartingWindowFromHiddenAboveTokenIfNeeded();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800394 }
395
396 // If we are preparing an app transition, then delay changing
397 // the visibility of this token until we execute that transition.
David Stevensf62360c2017-03-16 19:00:20 -0700398 if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800399 wtoken.inPendingTransaction = true;
400 if (visible) {
401 mService.mOpeningApps.add(wtoken);
402 wtoken.mEnteringAnimation = true;
403 } else {
404 mService.mClosingApps.add(wtoken);
405 wtoken.mEnteringAnimation = false;
406 }
407 if (mService.mAppTransition.getAppTransition()
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100408 == WindowManager.TRANSIT_TASK_OPEN_BEHIND) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800409 // We're launchingBehind, add the launching activity to mOpeningApps.
410 final WindowState win =
411 mService.getDefaultDisplayContentLocked().findFocusedWindow();
412 if (win != null) {
413 final AppWindowToken focusedToken = win.mAppToken;
414 if (focusedToken != null) {
415 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
416 + " adding " + focusedToken + " to mOpeningApps");
417 // Force animation to be loaded.
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200418 focusedToken.setHidden(true);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800419 mService.mOpeningApps.add(focusedToken);
420 }
421 }
422 }
423 return;
424 }
425
426 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
427 wtoken.updateReportedVisibilityLocked();
428 }
429 }
430
431 /**
432 * Notifies that we launched an app that might be visible or not visible depending on what kind
433 * of Keyguard flags it's going to set on its windows.
434 */
435 public void notifyUnknownVisibilityLaunched() {
436 synchronized(mWindowMap) {
437 if (mContainer != null) {
438 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
439 }
440 }
441 }
442
443 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
444 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700445 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700446 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800447 synchronized(mWindowMap) {
448 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200449 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask
450 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning
451 + " allowTaskSnapshot=" + allowTaskSnapshot);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800452
453 if (mContainer == null) {
454 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
455 return false;
456 }
457
458 // If the display is frozen, we won't do anything until the actual window is
459 // displayed so there is no reason to put in the starting window.
David Stevensf62360c2017-03-16 19:00:20 -0700460 if (!mContainer.okToDisplay()) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800461 return false;
462 }
463
464 if (mContainer.startingData != null) {
465 return false;
466 }
467
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700468 final WindowState mainWin = mContainer.findMainWindow();
Jorim Jaggie6b1b3b2017-07-24 16:44:18 +0200469 if (mainWin != null && mainWin.mWinAnimator.getShown()) {
470 // App already has a visible window...why would you want a starting window?
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700471 return false;
472 }
473
Jorim Jaggi42befc62017-06-13 11:54:04 -0700474 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
475 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
476 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggibae01b12017-04-11 16:29:10 -0700477 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700478 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800479
480 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700481 return createSnapshot(snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800482 }
483
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800484 // If this is a translucent window, then don't show a starting window -- the current
485 // effect (a full-screen opaque starting window that fades away to the real contents
486 // when it is ready) does not work for this.
487 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
488 + Integer.toHexString(theme));
489 if (theme != 0) {
490 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
491 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
492 if (ent == null) {
493 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
494 // see that.
495 return false;
496 }
497 final boolean windowIsTranslucent = ent.array.getBoolean(
498 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
499 final boolean windowIsFloating = ent.array.getBoolean(
500 com.android.internal.R.styleable.Window_windowIsFloating, false);
501 final boolean windowShowWallpaper = ent.array.getBoolean(
502 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
503 final boolean windowDisableStarting = ent.array.getBoolean(
504 com.android.internal.R.styleable.Window_windowDisablePreview, false);
505 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
506 + " Floating=" + windowIsFloating
507 + " ShowWallpaper=" + windowShowWallpaper);
508 if (windowIsTranslucent) {
509 return false;
510 }
511 if (windowIsFloating || windowDisableStarting) {
512 return false;
513 }
514 if (windowShowWallpaper) {
515 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
516 == null) {
517 // If this theme is requesting a wallpaper, and the wallpaper
518 // is not currently visible, then this effectively serves as
519 // an opaque window and our starting window transition animation
520 // can still work. We just need to make sure the starting window
521 // is also showing the wallpaper.
522 windowFlags |= FLAG_SHOW_WALLPAPER;
523 } else {
524 return false;
525 }
526 }
527 }
528
529 if (mContainer.transferStartingWindow(transferFrom)) {
530 return true;
531 }
532
Jorim Jaggi02886a82016-12-06 09:10:06 -0800533 // There is no existing starting window, and we don't want to create a splash screen, so
534 // that's it!
535 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800536 return false;
537 }
538
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200539 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SplashScreenStartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100540 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800541 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
542 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800543 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800544 }
545 return true;
546 }
547
Jorim Jaggibae01b12017-04-11 16:29:10 -0700548 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
Jorim Jaggi42befc62017-06-13 11:54:04 -0700549 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
550 TaskSnapshot snapshot) {
Matthew Ng606dd802017-06-05 14:06:32 -0700551 if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
552 // TODO(b/34099271): Remove this statement to add back the starting window and figure
553 // out why it causes flickering, the starting window appears over the thumbnail while
554 // the docked from recents transition occurs
555 return STARTING_WINDOW_TYPE_NONE;
556 } else if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800557 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700558 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700559 return snapshot == null ? STARTING_WINDOW_TYPE_NONE
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400560 : snapshotOrientationSameAsTask(snapshot) || fromRecents
Wale Ogunwaledfb7fb22017-06-23 14:52:40 -0700561 ? STARTING_WINDOW_TYPE_SNAPSHOT : STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800562 } else {
563 return STARTING_WINDOW_TYPE_NONE;
564 }
565 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800566
Jorim Jaggi02886a82016-12-06 09:10:06 -0800567 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800568 // Note: we really want to do sendMessageAtFrontOfQueue() because we
569 // want to process the message ASAP, before any other queued
570 // messages.
Jorim Jaggid8665f22018-04-10 00:34:24 +0200571 if (!mService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) {
572 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
573 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
574 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800575 }
576
Jorim Jaggi42befc62017-06-13 11:54:04 -0700577 private boolean createSnapshot(TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800578 if (snapshot == null) {
579 return false;
580 }
581
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200582 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating SnapshotStartingData");
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200583 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800584 scheduleAddStartingWindow();
585 return true;
586 }
587
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400588 private boolean snapshotOrientationSameAsTask(TaskSnapshot snapshot) {
Jorim Jaggi42befc62017-06-13 11:54:04 -0700589 if (snapshot == null) {
590 return false;
591 }
Jorim Jaggi1dda7a62017-06-28 14:40:27 -0400592 return mContainer.getTask().getConfiguration().orientation == snapshot.getOrientation();
Jorim Jaggi42befc62017-06-13 11:54:04 -0700593 }
594
Jorim Jaggi19be6052017-08-03 18:33:43 +0200595 public void removeStartingWindow() {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800596 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800597 if (mContainer.startingWindow == null) {
598 if (mContainer.startingData != null) {
599 // Starting window has not been added yet, but it is scheduled to be added.
600 // Go ahead and cancel the request.
601 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
602 "Clearing startingData for token=" + mContainer);
603 mContainer.startingData = null;
604 }
605 return;
606 }
607
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700608 final StartingSurface surface;
609 if (mContainer.startingData != null) {
610 surface = mContainer.startingSurface;
611 mContainer.startingData = null;
612 mContainer.startingSurface = null;
613 mContainer.startingWindow = null;
614 mContainer.startingDisplayed = false;
Seigo Nonakaeafe7372017-08-16 12:39:49 -0700615 if (surface == null) {
616 if (DEBUG_STARTING_WINDOW) {
617 Slog.v(TAG_WM, "startingWindow was set but startingSurface==null, couldn't "
618 + "remove");
619 }
620 return;
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700621 }
622 } else {
623 if (DEBUG_STARTING_WINDOW) {
624 Slog.v(TAG_WM, "Tried to remove starting window but startingWindow was null:"
625 + mContainer);
626 }
627 return;
628 }
629
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200630 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Schedule remove starting " + mContainer
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700631 + " startingWindow=" + mContainer.startingWindow
Jorim Jaggi77d0f36c2018-03-16 17:49:49 +0100632 + " startingView=" + mContainer.startingSurface
633 + " Callers=" + Debug.getCallers(5));
Jorim Jaggia3382192017-07-18 14:33:21 +0200634
635 // Use the same thread to remove the window as we used to add it, as otherwise we end up
636 // with things in the view hierarchy being called from different threads.
Jorim Jaggi8829cf12017-09-05 12:28:52 +0200637 mService.mAnimationHandler.post(() -> {
Seigo Nonaka82871bd2017-07-17 20:22:44 -0700638 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Removing startingView=" + surface);
639 try {
640 surface.remove();
641 } catch (Exception e) {
642 Slog.w(TAG_WM, "Exception when removing starting window", e);
643 }
644 });
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800645 }
646 }
647
648 public void pauseKeyDispatching() {
649 synchronized (mWindowMap) {
650 if (mContainer != null) {
651 mService.mInputMonitor.pauseDispatchingLw(mContainer);
652 }
653 }
654 }
655
656 public void resumeKeyDispatching() {
657 synchronized (mWindowMap) {
658 if (mContainer != null) {
659 mService.mInputMonitor.resumeDispatchingLw(mContainer);
660 }
661 }
662 }
663
Jorim Jaggibae01b12017-04-11 16:29:10 -0700664 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800665 synchronized(mWindowMap) {
666 if (mContainer == null) {
667 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
668 return;
669 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700670 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800671 }
672 }
673
Robert Carr29daa922018-04-27 11:56:48 -0700674 public void notifyAppStopping() {
675 synchronized(mWindowMap) {
676 if (mContainer == null) {
677 Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: "
678 + mToken);
679 return;
680 }
681 mContainer.detachChildren();
682 }
683 }
684
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800685 public void notifyAppStopped() {
686 synchronized(mWindowMap) {
687 if (mContainer == null) {
688 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
689 + mToken);
690 return;
691 }
692 mContainer.notifyAppStopped();
693 }
694 }
695
696 public void startFreezingScreen(int configChanges) {
697 synchronized(mWindowMap) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800698 if (mContainer == null) {
699 Slog.w(TAG_WM,
700 "Attempted to freeze screen with non-existing app token: " + mContainer);
701 return;
702 }
David Stevensf62360c2017-03-16 19:00:20 -0700703
704 if (configChanges == 0 && mContainer.okToDisplay()) {
705 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
706 return;
707 }
708
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800709 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800710 }
711 }
712
713 public void stopFreezingScreen(boolean force) {
714 synchronized(mWindowMap) {
715 if (mContainer == null) {
716 return;
717 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800718 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
Jorim Jaggib0fc8172017-11-23 17:04:08 +0000719 + mContainer.isHidden() + " freezing=" + mContainer.isFreezingScreen());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800720 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800721 }
722 }
723
Jorim Jaggif84e2f62018-01-16 14:17:59 +0100724 public void registerRemoteAnimations(RemoteAnimationDefinition definition) {
725 synchronized (mWindowMap) {
726 if (mContainer == null) {
727 Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app"
728 + " token: " + mToken);
729 return;
730 }
731 mContainer.registerRemoteAnimations(definition);
732 }
733 }
734
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800735 void reportStartingWindowDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700736 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800737 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800738
739 void reportWindowsDrawn() {
Sudheer Shankac766db02017-06-12 10:37:29 -0700740 mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_WINDOWS_DRAWN));
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800741 }
742
743 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800744 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800745 }
746
747 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800748 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800749 }
750
751 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700752 boolean keyDispatchingTimedOut(String reason, int windowPid) {
753 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800754 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800755
756 @Override
757 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700758 return "AppWindowContainerController{"
759 + " token=" + mToken
760 + " mContainer=" + mContainer
761 + " mListener=" + mListener
762 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800763 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800764}