blob: b5e194b4b93b6390a6c9359ebb44b374f02034a1 [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;
22import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
23import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
24import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
27import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
29import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080030
Jorim Jaggie2c77f92016-12-29 14:57:22 +010031import android.app.ActivityManager.TaskSnapshot;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080032import android.content.res.CompatibilityInfo;
33import android.content.res.Configuration;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080034import android.graphics.Bitmap;
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -070035import android.graphics.Rect;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080036import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080037import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080038import android.os.IBinder;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080039import android.os.Trace;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080040import android.util.Slog;
41import android.view.IApplicationToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080042import android.view.WindowManagerPolicy.StartingSurface;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080043
Winson Chung30480042017-01-26 10:55:34 -080044import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080045import com.android.server.AttributeCache;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080046/**
47 * Controller for the app window token container. This is created by activity manager to link
48 * activity records to the app window token container they use in window manager.
49 *
50 * Test class: {@link AppWindowContainerControllerTests}
51 */
52public class AppWindowContainerController
53 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
54
Jorim Jaggi02886a82016-12-06 09:10:06 -080055 private static final int STARTING_WINDOW_TYPE_NONE = 0;
56 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
57 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
58
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080059 private final IApplicationToken mToken;
Jorim Jaggi9bafc712017-01-19 17:28:30 +010060 private final Handler mHandler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080061
Jorim Jaggi3878ca32017-02-02 17:13:05 -080062 private final Runnable mOnStartingWindowDrawn = () -> {
63 if (mListener == null) {
64 return;
65 }
66 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
67 + AppWindowContainerController.this.mToken);
68 mListener.onStartingWindowDrawn();
69 };
70
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080071 private final Runnable mOnWindowsDrawn = () -> {
72 if (mListener == null) {
73 return;
74 }
75 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
76 + AppWindowContainerController.this.mToken);
77 mListener.onWindowsDrawn();
78 };
79
80 private final Runnable mOnWindowsVisible = () -> {
81 if (mListener == null) {
82 return;
83 }
84 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
85 + AppWindowContainerController.this.mToken);
86 mListener.onWindowsVisible();
87 };
88
89 private final Runnable mOnWindowsGone = () -> {
90 if (mListener == null) {
91 return;
92 }
93 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
94 + AppWindowContainerController.this.mToken);
95 mListener.onWindowsGone();
96 };
97
Jorim Jaggi02886a82016-12-06 09:10:06 -080098 private final Runnable mRemoveStartingWindow = () -> {
99 StartingSurface surface = null;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800100 synchronized (mWindowMap) {
101 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
102 + ": startingWindow=" + mContainer.startingWindow
103 + " startingView=" + mContainer.startingSurface);
Jorim Jaggi553cec62017-01-13 13:00:42 +0100104 if (mContainer == null) {
105 return;
106 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800107 if (mContainer.startingWindow != null) {
108 surface = mContainer.startingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800109 mContainer.startingData = null;
110 mContainer.startingSurface = null;
111 mContainer.startingWindow = null;
112 mContainer.startingDisplayed = false;
113 }
114 }
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100115 if (surface != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800116 try {
117 surface.remove();
118 } catch (Exception e) {
119 Slog.w(TAG_WM, "Exception when removing starting window", e);
120 }
121 }
122 };
123
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800124 private final Runnable mAddStartingWindow = () -> {
125 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100126 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800127
128 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100129 if (mContainer == null) {
130 return;
131 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800132 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100133 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800134 }
135
136 if (startingData == null) {
137 // Animation has been canceled... do nothing.
138 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 Jaggie09fc6b2017-01-19 15:33:36 +0100153 if (container.removed || container.startingData == null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800154 // If the window was successfully added, then
155 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100156 if (container.startingWindow != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800157 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100158 "Aborted starting " + container
159 + ": removed=" + container.removed
160 + " startingData=" + container.startingData);
161 container.startingWindow = null;
162 container.startingData = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800163 abort = true;
164 }
165 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100166 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800167 }
168 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
169 "Added starting " + mContainer
170 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100171 + container.startingWindow + " startingView="
172 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800173 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800174 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100175 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800176 }
177 }
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,
185 Configuration overrideConfig, 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 Ogunwale55ddf8f2017-03-20 08:56:38 -0700190 WindowManagerService.getInstance(), overrideConfig, 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 Ogunwale55ddf8f2017-03-20 08:56:38 -0700198 WindowManagerService service, Configuration overrideConfig, Rect bounds) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800199 super(listener, service);
Jorim Jaggi9bafc712017-01-19 17:28:30 +0100200 mHandler = new Handler(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 Ogunwale55ddf8f2017-03-20 08:56:38 -0700219 alwaysFocusable, this, overrideConfig, 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 Ogunwale55ddf8f2017-03-20 08:56:38 -0700231 boolean alwaysFocusable, AppWindowContainerController controller,
232 Configuration overrideConfig, Rect bounds) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100233 return new AppWindowToken(service, token, voiceInteraction, dc,
Winson Chung30480042017-01-26 10:55:34 -0800234 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
235 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700236 controller, overrideConfig, bounds);
Winson Chung30480042017-01-26 10:55:34 -0800237 }
238
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800239 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800240 synchronized(mWindowMap) {
241 final DisplayContent dc = mRoot.getDisplayContent(displayId);
242 if (dc == null) {
243 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
244 + mToken + " from non-existing displayId=" + displayId);
245 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800246 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800247 dc.removeAppToken(mToken.asBinder());
248 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800249 }
250 }
251
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800252 @Override
253 public void removeContainer() {
254 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800255 }
256
Winson Chung30480042017-01-26 10:55:34 -0800257 public void reparent(TaskWindowContainerController taskController, int position) {
258 synchronized (mWindowMap) {
259 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
260 + " to task=" + taskController + " at " + position);
261 if (mContainer == null) {
262 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
263 "reparent: could not find app token=" + mToken);
264 return;
265 }
266 final Task task = taskController.mContainer;
267 if (task == null) {
268 throw new IllegalArgumentException("reparent: could not find task="
269 + taskController);
270 }
271 mContainer.reparent(task, position);
272 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
273 }
274 }
275
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800276 public Configuration setOrientation(int requestedOrientation, int displayId,
277 Configuration displayConfig, boolean freezeScreenIfNeeded) {
278 synchronized(mWindowMap) {
279 if (mContainer == null) {
280 Slog.w(TAG_WM,
281 "Attempted to set orientation of non-existing app token: " + mToken);
282 return null;
283 }
284
285 mContainer.setOrientation(requestedOrientation);
286
287 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
288 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
289
290 }
291 }
292
293 public int getOrientation() {
294 synchronized(mWindowMap) {
295 if (mContainer == null) {
296 return SCREEN_ORIENTATION_UNSPECIFIED;
297 }
298
299 return mContainer.getOrientationIgnoreVisibility();
300 }
301 }
302
Wale Ogunwale55ddf8f2017-03-20 08:56:38 -0700303 // TODO(b/36505427): Maybe move to WindowContainerController so other sub-classes can use it as
304 // a generic way to set override config. Need to untangle current ways the override config is
305 // currently set for tasks and displays before we are doing that though.
306 public void onOverrideConfigurationChanged(Configuration overrideConfiguration, Rect bounds) {
307 synchronized(mWindowMap) {
308 if (mContainer != null) {
309 mContainer.onOverrideConfigurationChanged(overrideConfiguration, bounds);
310 }
311 }
312 }
313
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100314 public void setDisablePreviewScreenshots(boolean disable) {
315 synchronized (mWindowMap) {
316 if (mContainer == null) {
317 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app"
318 + " token: " + mToken);
319 return;
320 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200321 mContainer.setDisablePreviewScreenshots(disable);
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100322 }
323 }
324
Wale Ogunwale89973222017-04-23 18:39:45 -0700325 public void setVisibility(boolean visible, boolean deferHidingClient) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800326 synchronized(mWindowMap) {
327 if (mContainer == null) {
328 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
329 + mToken);
330 return;
331 }
332
333 final AppWindowToken wtoken = mContainer;
334
335 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
336 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
337 + " hidden=" + wtoken.hidden + " hiddenRequested="
338 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
339
340 mService.mOpeningApps.remove(wtoken);
341 mService.mClosingApps.remove(wtoken);
342 wtoken.waitingToShow = false;
343 wtoken.hiddenRequested = !visible;
Wale Ogunwale89973222017-04-23 18:39:45 -0700344 wtoken.mDeferHidingClient = deferHidingClient;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800345
346 if (!visible) {
347 // If the app is dead while it was visible, we kept its dead window on screen.
348 // Now that the app is going invisible, we can remove it. It will be restarted
349 // if made visible again.
350 wtoken.removeDeadWindows();
351 wtoken.setVisibleBeforeClientHidden();
352 } else {
353 if (!mService.mAppTransition.isTransitionSet()
354 && mService.mAppTransition.isReady()) {
355 // Add the app mOpeningApps if transition is unset but ready. This means
356 // we're doing a screen freeze, and the unfreeze will wait for all opening
357 // apps to be ready.
358 mService.mOpeningApps.add(wtoken);
359 }
360 wtoken.startingMoved = false;
361 // If the token is currently hidden (should be the common case), or has been
362 // stopped, then we need to set up to wait for its windows to be ready.
363 if (wtoken.hidden || wtoken.mAppStopped) {
364 wtoken.clearAllDrawn();
365
366 // If the app was already visible, don't reset the waitingToShow state.
367 if (wtoken.hidden) {
368 wtoken.waitingToShow = true;
369 }
370
Wale Ogunwale89973222017-04-23 18:39:45 -0700371 if (wtoken.isClientHidden()) {
372 // In the case where we are making an app visible but holding off for a
373 // transition, we still need to tell the client to make its windows visible
374 // so they get drawn. Otherwise, we will wait on performing the transition
375 // until all windows have been drawn, they never will be, and we are sad.
376 wtoken.setClientHidden(false);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800377 }
378 }
379 wtoken.requestUpdateWallpaperIfNeeded();
380
381 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
382 wtoken.mAppStopped = false;
383 }
384
385 // If we are preparing an app transition, then delay changing
386 // the visibility of this token until we execute that transition.
387 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
388 // A dummy animation is a placeholder animation which informs others that an
389 // animation is going on (in this case an application transition). If the animation
390 // was transferred from another application/animator, no dummy animator should be
391 // created since an animation is already in progress.
392 if (wtoken.mAppAnimator.usingTransferredAnimation
393 && wtoken.mAppAnimator.animation == null) {
394 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
395 + ", using null transferred animation!");
396 }
397 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
398 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
399 if (DEBUG_APP_TRANSITIONS) Slog.v(
400 TAG_WM, "Setting dummy animation on: " + wtoken);
401 wtoken.mAppAnimator.setDummyAnimation();
402 }
403 wtoken.inPendingTransaction = true;
404 if (visible) {
405 mService.mOpeningApps.add(wtoken);
406 wtoken.mEnteringAnimation = true;
407 } else {
408 mService.mClosingApps.add(wtoken);
409 wtoken.mEnteringAnimation = false;
410 }
411 if (mService.mAppTransition.getAppTransition()
412 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
413 // We're launchingBehind, add the launching activity to mOpeningApps.
414 final WindowState win =
415 mService.getDefaultDisplayContentLocked().findFocusedWindow();
416 if (win != null) {
417 final AppWindowToken focusedToken = win.mAppToken;
418 if (focusedToken != null) {
419 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
420 + " adding " + focusedToken + " to mOpeningApps");
421 // Force animation to be loaded.
422 focusedToken.hidden = true;
423 mService.mOpeningApps.add(focusedToken);
424 }
425 }
426 }
427 return;
428 }
429
430 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
431 wtoken.updateReportedVisibilityLocked();
432 }
433 }
434
435 /**
436 * Notifies that we launched an app that might be visible or not visible depending on what kind
437 * of Keyguard flags it's going to set on its windows.
438 */
439 public void notifyUnknownVisibilityLaunched() {
440 synchronized(mWindowMap) {
441 if (mContainer != null) {
442 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
443 }
444 }
445 }
446
447 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
448 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggibae01b12017-04-11 16:29:10 -0700449 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning,
450 boolean allowTaskSnapshot) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800451 synchronized(mWindowMap) {
452 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
453 + " pkg=" + pkg + " transferFrom=" + transferFrom);
454
455 if (mContainer == null) {
456 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
457 return false;
458 }
459
460 // If the display is frozen, we won't do anything until the actual window is
461 // displayed so there is no reason to put in the starting window.
462 if (!mService.okToDisplay()) {
463 return false;
464 }
465
466 if (mContainer.startingData != null) {
467 return false;
468 }
469
Wale Ogunwale4ba3e832017-04-20 16:45:13 -0700470 final WindowState mainWin = mContainer.findMainWindow();
471 if (mainWin != null && mainWin.isVisible() && mainWin.isDrawnLw()) {
472 // App already has a visible window that is drawn...why would you want a starting
473 // window?
474 return false;
475 }
476
Jorim Jaggibae01b12017-04-11 16:29:10 -0700477 final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
478 allowTaskSnapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800479
480 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
481 return createSnapshot();
482 }
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
539 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
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,
549 boolean allowTaskSnapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800550 if (newTask || !processRunning) {
551 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
Jorim Jaggibae01b12017-04-11 16:29:10 -0700552 } else if (taskSwitch && allowTaskSnapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800553 return STARTING_WINDOW_TYPE_SNAPSHOT;
554 } else {
555 return STARTING_WINDOW_TYPE_NONE;
556 }
557 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800558
Jorim Jaggi02886a82016-12-06 09:10:06 -0800559 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800560 // Note: we really want to do sendMessageAtFrontOfQueue() because we
561 // want to process the message ASAP, before any other queued
562 // messages.
563 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
Jorim Jaggied7993b2017-03-28 18:50:01 +0100564 mService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800565 }
566
Jorim Jaggi02886a82016-12-06 09:10:06 -0800567 private boolean createSnapshot() {
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100568 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
Bryce Lee6d410262017-02-28 15:30:17 -0800569 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
Jorim Jaggi35e3f532017-03-17 17:06:50 +0100570 false /* restoreFromDisk */, false /* reducedResolution */);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800571
572 if (snapshot == null) {
573 return false;
574 }
575
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200576 mContainer.startingData = new SnapshotStartingData(mService, snapshot);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800577 scheduleAddStartingWindow();
578 return true;
579 }
580
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800581 public void removeStartingWindow() {
582 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800583 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
584 // Already scheduled.
585 return;
586 }
587
588 if (mContainer.startingWindow == null) {
589 if (mContainer.startingData != null) {
590 // Starting window has not been added yet, but it is scheduled to be added.
591 // Go ahead and cancel the request.
592 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
593 "Clearing startingData for token=" + mContainer);
594 mContainer.startingData = null;
595 }
596 return;
597 }
598
599 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1)
600 + ": Schedule remove starting " + mContainer
601 + " startingWindow=" + mContainer.startingWindow);
602 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800603 }
604 }
605
606 public void pauseKeyDispatching() {
607 synchronized (mWindowMap) {
608 if (mContainer != null) {
609 mService.mInputMonitor.pauseDispatchingLw(mContainer);
610 }
611 }
612 }
613
614 public void resumeKeyDispatching() {
615 synchronized (mWindowMap) {
616 if (mContainer != null) {
617 mService.mInputMonitor.resumeDispatchingLw(mContainer);
618 }
619 }
620 }
621
Jorim Jaggibae01b12017-04-11 16:29:10 -0700622 public void notifyAppResumed(boolean wasStopped) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800623 synchronized(mWindowMap) {
624 if (mContainer == null) {
625 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
626 return;
627 }
Jorim Jaggibae01b12017-04-11 16:29:10 -0700628 mContainer.notifyAppResumed(wasStopped);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800629 }
630 }
631
632 public void notifyAppStopped() {
633 synchronized(mWindowMap) {
634 if (mContainer == null) {
635 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
636 + mToken);
637 return;
638 }
639 mContainer.notifyAppStopped();
640 }
641 }
642
643 public void startFreezingScreen(int configChanges) {
644 synchronized(mWindowMap) {
645 if (configChanges == 0 && mService.okToDisplay()) {
646 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
647 return;
648 }
649
650 if (mContainer == null) {
651 Slog.w(TAG_WM,
652 "Attempted to freeze screen with non-existing app token: " + mContainer);
653 return;
654 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800655 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800656 }
657 }
658
659 public void stopFreezingScreen(boolean force) {
660 synchronized(mWindowMap) {
661 if (mContainer == null) {
662 return;
663 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800664 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
665 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
666 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800667 }
668 }
669
670 /**
671 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
672 * In portrait mode, it grabs the full screenshot.
673 *
674 * @param displayId the Display to take a screenshot of.
675 * @param width the width of the target bitmap
676 * @param height the height of the target bitmap
677 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
678 */
679 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
680 try {
681 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
682 final DisplayContent dc;
683 synchronized(mWindowMap) {
684 dc = mRoot.getDisplayContentOrCreate(displayId);
685 if (dc == null) {
686 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
687 + ": returning null. No Display for displayId=" + displayId);
688 return null;
689 }
690 }
691 return dc.screenshotApplications(mToken.asBinder(), width, height,
692 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100693 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800694 } finally {
695 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
696 }
697 }
698
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800699 void reportStartingWindowDrawn() {
700 mHandler.post(mOnStartingWindowDrawn);
701 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800702
703 void reportWindowsDrawn() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800704 mHandler.post(mOnWindowsDrawn);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800705 }
706
707 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800708 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800709 }
710
711 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800712 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800713 }
714
715 /** Calls directly into activity manager so window manager lock shouldn't held. */
Wale Ogunwale7402ddf2017-03-29 12:58:24 -0700716 boolean keyDispatchingTimedOut(String reason, int windowPid) {
717 return mListener != null && mListener.keyDispatchingTimedOut(reason, windowPid);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800718 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800719
720 @Override
721 public String toString() {
Wale Ogunwale9c64cb62017-04-12 13:39:59 -0700722 return "AppWindowContainerController{"
723 + " token=" + mToken
724 + " mContainer=" + mContainer
725 + " mListener=" + mListener
726 + "}";
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800727 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800728}