blob: b90a82a886412785ef0a7df6448379de0c7716fb [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 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;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080038import android.os.Looper;
39import 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,
184 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800185 this(taskController, token, listener, index, requestedOrientation, fullscreen,
186 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800187 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
188 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
189 WindowManagerService.getInstance());
190 }
191
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800192 public AppWindowContainerController(TaskWindowContainerController taskController,
193 IApplicationToken token, AppWindowContainerListener listener, int index,
194 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800195 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
196 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
197 WindowManagerService service) {
198 super(listener, service);
Jorim Jaggi9bafc712017-01-19 17:28:30 +0100199 mHandler = new Handler(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800200 mToken = token;
201 synchronized(mWindowMap) {
202 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
203 if (atoken != null) {
204 // TODO: Should this throw an exception instead?
205 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
206 return;
207 }
208
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800209 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800210 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800211 throw new IllegalArgumentException("AppWindowContainerController: invalid "
212 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800213 }
214
Winson Chung30480042017-01-26 10:55:34 -0800215 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800216 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
217 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
218 alwaysFocusable, this);
219 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800220 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800221 task.addChild(atoken, index);
222 }
223 }
224
Winson Chung30480042017-01-26 10:55:34 -0800225 @VisibleForTesting
226 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
227 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
228 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
229 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
230 boolean alwaysFocusable, AppWindowContainerController controller) {
231 return new AppWindowToken(service, token, voiceInteraction, dc,
232 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
233 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
234 controller);
235 }
236
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800237 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800238 synchronized(mWindowMap) {
239 final DisplayContent dc = mRoot.getDisplayContent(displayId);
240 if (dc == null) {
241 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
242 + mToken + " from non-existing displayId=" + displayId);
243 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800244 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800245 dc.removeAppToken(mToken.asBinder());
246 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800247 }
248 }
249
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800250 @Override
251 public void removeContainer() {
252 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800253 }
254
Winson Chung30480042017-01-26 10:55:34 -0800255 public void reparent(TaskWindowContainerController taskController, int position) {
256 synchronized (mWindowMap) {
257 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
258 + " to task=" + taskController + " at " + position);
259 if (mContainer == null) {
260 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
261 "reparent: could not find app token=" + mToken);
262 return;
263 }
264 final Task task = taskController.mContainer;
265 if (task == null) {
266 throw new IllegalArgumentException("reparent: could not find task="
267 + taskController);
268 }
269 mContainer.reparent(task, position);
270 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
271 }
272 }
273
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800274 public Configuration setOrientation(int requestedOrientation, int displayId,
275 Configuration displayConfig, boolean freezeScreenIfNeeded) {
276 synchronized(mWindowMap) {
277 if (mContainer == null) {
278 Slog.w(TAG_WM,
279 "Attempted to set orientation of non-existing app token: " + mToken);
280 return null;
281 }
282
283 mContainer.setOrientation(requestedOrientation);
284
285 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
286 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
287
288 }
289 }
290
291 public int getOrientation() {
292 synchronized(mWindowMap) {
293 if (mContainer == null) {
294 return SCREEN_ORIENTATION_UNSPECIFIED;
295 }
296
297 return mContainer.getOrientationIgnoreVisibility();
298 }
299 }
300
301 public void setVisibility(boolean visible) {
302 synchronized(mWindowMap) {
303 if (mContainer == null) {
304 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
305 + mToken);
306 return;
307 }
308
309 final AppWindowToken wtoken = mContainer;
310
311 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
312 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
313 + " hidden=" + wtoken.hidden + " hiddenRequested="
314 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
315
316 mService.mOpeningApps.remove(wtoken);
317 mService.mClosingApps.remove(wtoken);
318 wtoken.waitingToShow = false;
319 wtoken.hiddenRequested = !visible;
320
321 if (!visible) {
322 // If the app is dead while it was visible, we kept its dead window on screen.
323 // Now that the app is going invisible, we can remove it. It will be restarted
324 // if made visible again.
325 wtoken.removeDeadWindows();
326 wtoken.setVisibleBeforeClientHidden();
327 } else {
328 if (!mService.mAppTransition.isTransitionSet()
329 && mService.mAppTransition.isReady()) {
330 // Add the app mOpeningApps if transition is unset but ready. This means
331 // we're doing a screen freeze, and the unfreeze will wait for all opening
332 // apps to be ready.
333 mService.mOpeningApps.add(wtoken);
334 }
335 wtoken.startingMoved = false;
336 // If the token is currently hidden (should be the common case), or has been
337 // stopped, then we need to set up to wait for its windows to be ready.
338 if (wtoken.hidden || wtoken.mAppStopped) {
339 wtoken.clearAllDrawn();
340
341 // If the app was already visible, don't reset the waitingToShow state.
342 if (wtoken.hidden) {
343 wtoken.waitingToShow = true;
344 }
345
346 if (wtoken.clientHidden) {
347 // In the case where we are making an app visible
348 // but holding off for a transition, we still need
349 // to tell the client to make its windows visible so
350 // they get drawn. Otherwise, we will wait on
351 // performing the transition until all windows have
352 // been drawn, they never will be, and we are sad.
353 wtoken.clientHidden = false;
354 wtoken.sendAppVisibilityToClients();
355 }
356 }
357 wtoken.requestUpdateWallpaperIfNeeded();
358
359 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
360 wtoken.mAppStopped = false;
361 }
362
363 // If we are preparing an app transition, then delay changing
364 // the visibility of this token until we execute that transition.
365 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
366 // A dummy animation is a placeholder animation which informs others that an
367 // animation is going on (in this case an application transition). If the animation
368 // was transferred from another application/animator, no dummy animator should be
369 // created since an animation is already in progress.
370 if (wtoken.mAppAnimator.usingTransferredAnimation
371 && wtoken.mAppAnimator.animation == null) {
372 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
373 + ", using null transferred animation!");
374 }
375 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
376 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
377 if (DEBUG_APP_TRANSITIONS) Slog.v(
378 TAG_WM, "Setting dummy animation on: " + wtoken);
379 wtoken.mAppAnimator.setDummyAnimation();
380 }
381 wtoken.inPendingTransaction = true;
382 if (visible) {
383 mService.mOpeningApps.add(wtoken);
384 wtoken.mEnteringAnimation = true;
385 } else {
386 mService.mClosingApps.add(wtoken);
387 wtoken.mEnteringAnimation = false;
388 }
389 if (mService.mAppTransition.getAppTransition()
390 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
391 // We're launchingBehind, add the launching activity to mOpeningApps.
392 final WindowState win =
393 mService.getDefaultDisplayContentLocked().findFocusedWindow();
394 if (win != null) {
395 final AppWindowToken focusedToken = win.mAppToken;
396 if (focusedToken != null) {
397 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
398 + " adding " + focusedToken + " to mOpeningApps");
399 // Force animation to be loaded.
400 focusedToken.hidden = true;
401 mService.mOpeningApps.add(focusedToken);
402 }
403 }
404 }
405 return;
406 }
407
408 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
409 wtoken.updateReportedVisibilityLocked();
410 }
411 }
412
413 /**
414 * Notifies that we launched an app that might be visible or not visible depending on what kind
415 * of Keyguard flags it's going to set on its windows.
416 */
417 public void notifyUnknownVisibilityLaunched() {
418 synchronized(mWindowMap) {
419 if (mContainer != null) {
420 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
421 }
422 }
423 }
424
425 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
426 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800427 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800428 synchronized(mWindowMap) {
429 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
430 + " pkg=" + pkg + " transferFrom=" + transferFrom);
431
432 if (mContainer == null) {
433 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
434 return false;
435 }
436
437 // If the display is frozen, we won't do anything until the actual window is
438 // displayed so there is no reason to put in the starting window.
439 if (!mService.okToDisplay()) {
440 return false;
441 }
442
443 if (mContainer.startingData != null) {
444 return false;
445 }
446
Jorim Jaggi02886a82016-12-06 09:10:06 -0800447 final int type = getStartingWindowType(newTask, taskSwitch, processRunning);
448
449 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
450 return createSnapshot();
451 }
452
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800453 // If this is a translucent window, then don't show a starting window -- the current
454 // effect (a full-screen opaque starting window that fades away to the real contents
455 // when it is ready) does not work for this.
456 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
457 + Integer.toHexString(theme));
458 if (theme != 0) {
459 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
460 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
461 if (ent == null) {
462 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
463 // see that.
464 return false;
465 }
466 final boolean windowIsTranslucent = ent.array.getBoolean(
467 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
468 final boolean windowIsFloating = ent.array.getBoolean(
469 com.android.internal.R.styleable.Window_windowIsFloating, false);
470 final boolean windowShowWallpaper = ent.array.getBoolean(
471 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
472 final boolean windowDisableStarting = ent.array.getBoolean(
473 com.android.internal.R.styleable.Window_windowDisablePreview, false);
474 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
475 + " Floating=" + windowIsFloating
476 + " ShowWallpaper=" + windowShowWallpaper);
477 if (windowIsTranslucent) {
478 return false;
479 }
480 if (windowIsFloating || windowDisableStarting) {
481 return false;
482 }
483 if (windowShowWallpaper) {
484 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
485 == null) {
486 // If this theme is requesting a wallpaper, and the wallpaper
487 // is not currently visible, then this effectively serves as
488 // an opaque window and our starting window transition animation
489 // can still work. We just need to make sure the starting window
490 // is also showing the wallpaper.
491 windowFlags |= FLAG_SHOW_WALLPAPER;
492 } else {
493 return false;
494 }
495 }
496 }
497
498 if (mContainer.transferStartingWindow(transferFrom)) {
499 return true;
500 }
501
Jorim Jaggi02886a82016-12-06 09:10:06 -0800502 // There is no existing starting window, and we don't want to create a splash screen, so
503 // that's it!
504 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800505 return false;
506 }
507
508 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100509 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800510 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
511 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800512 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800513 }
514 return true;
515 }
516
Jorim Jaggi02886a82016-12-06 09:10:06 -0800517 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning) {
518 if (newTask || !processRunning) {
519 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
520 } else if (taskSwitch) {
521 return STARTING_WINDOW_TYPE_SNAPSHOT;
522 } else {
523 return STARTING_WINDOW_TYPE_NONE;
524 }
525 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800526
Jorim Jaggi02886a82016-12-06 09:10:06 -0800527 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800528 // Note: we really want to do sendMessageAtFrontOfQueue() because we
529 // want to process the message ASAP, before any other queued
530 // messages.
531 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
532 mHandler.postAtFrontOfQueue(mAddStartingWindow);
533 }
534
Jorim Jaggi02886a82016-12-06 09:10:06 -0800535 private boolean createSnapshot() {
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100536 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
Bryce Lee6d410262017-02-28 15:30:17 -0800537 mContainer.getTask().mTaskId, mContainer.getTask().mUserId,
538 false /* restoreFromDisk */);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800539
540 if (snapshot == null) {
541 return false;
542 }
543
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100544 mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800545 scheduleAddStartingWindow();
546 return true;
547 }
548
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800549 public void removeStartingWindow() {
550 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800551 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
552 // Already scheduled.
553 return;
554 }
555
556 if (mContainer.startingWindow == null) {
557 if (mContainer.startingData != null) {
558 // Starting window has not been added yet, but it is scheduled to be added.
559 // Go ahead and cancel the request.
560 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
561 "Clearing startingData for token=" + mContainer);
562 mContainer.startingData = null;
563 }
564 return;
565 }
566
567 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1)
568 + ": Schedule remove starting " + mContainer
569 + " startingWindow=" + mContainer.startingWindow);
570 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800571 }
572 }
573
574 public void pauseKeyDispatching() {
575 synchronized (mWindowMap) {
576 if (mContainer != null) {
577 mService.mInputMonitor.pauseDispatchingLw(mContainer);
578 }
579 }
580 }
581
582 public void resumeKeyDispatching() {
583 synchronized (mWindowMap) {
584 if (mContainer != null) {
585 mService.mInputMonitor.resumeDispatchingLw(mContainer);
586 }
587 }
588 }
589
590 public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
591 synchronized(mWindowMap) {
592 if (mContainer == null) {
593 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
594 return;
595 }
596 mContainer.notifyAppResumed(wasStopped, allowSavedSurface);
597 }
598 }
599
600 public void notifyAppStopped() {
601 synchronized(mWindowMap) {
602 if (mContainer == null) {
603 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
604 + mToken);
605 return;
606 }
607 mContainer.notifyAppStopped();
608 }
609 }
610
611 public void startFreezingScreen(int configChanges) {
612 synchronized(mWindowMap) {
613 if (configChanges == 0 && mService.okToDisplay()) {
614 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
615 return;
616 }
617
618 if (mContainer == null) {
619 Slog.w(TAG_WM,
620 "Attempted to freeze screen with non-existing app token: " + mContainer);
621 return;
622 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800623 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800624 }
625 }
626
627 public void stopFreezingScreen(boolean force) {
628 synchronized(mWindowMap) {
629 if (mContainer == null) {
630 return;
631 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800632 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
633 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
634 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800635 }
636 }
637
638 /**
639 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
640 * In portrait mode, it grabs the full screenshot.
641 *
642 * @param displayId the Display to take a screenshot of.
643 * @param width the width of the target bitmap
644 * @param height the height of the target bitmap
645 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
646 */
647 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
648 try {
649 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
650 final DisplayContent dc;
651 synchronized(mWindowMap) {
652 dc = mRoot.getDisplayContentOrCreate(displayId);
653 if (dc == null) {
654 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
655 + ": returning null. No Display for displayId=" + displayId);
656 return null;
657 }
658 }
659 return dc.screenshotApplications(mToken.asBinder(), width, height,
660 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100661 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800662 } finally {
663 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
664 }
665 }
666
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800667 void reportStartingWindowDrawn() {
668 mHandler.post(mOnStartingWindowDrawn);
669 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800670
671 void reportWindowsDrawn() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800672 mHandler.post(mOnWindowsDrawn);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800673 }
674
675 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800676 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800677 }
678
679 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800680 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800681 }
682
683 /** Calls directly into activity manager so window manager lock shouldn't held. */
684 boolean keyDispatchingTimedOut(String reason) {
685 return mListener != null && mListener.keyDispatchingTimedOut(reason);
686 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800687
688 @Override
689 public String toString() {
690 return "{AppWindowContainerController token=" + mToken + "}";
691 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800692}