blob: 3a86874b1f4e14c3a89ba95c0f9daf5d433d3737 [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
62 private final Runnable mOnWindowsDrawn = () -> {
63 if (mListener == null) {
64 return;
65 }
66 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
67 + AppWindowContainerController.this.mToken);
68 mListener.onWindowsDrawn();
69 };
70
71 private final Runnable mOnWindowsVisible = () -> {
72 if (mListener == null) {
73 return;
74 }
75 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
76 + AppWindowContainerController.this.mToken);
77 mListener.onWindowsVisible();
78 };
79
80 private final Runnable mOnWindowsGone = () -> {
81 if (mListener == null) {
82 return;
83 }
84 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
85 + AppWindowContainerController.this.mToken);
86 mListener.onWindowsGone();
87 };
88
Jorim Jaggi02886a82016-12-06 09:10:06 -080089 private final Runnable mRemoveStartingWindow = () -> {
90 StartingSurface surface = null;
Jorim Jaggi02886a82016-12-06 09:10:06 -080091 synchronized (mWindowMap) {
92 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
93 + ": startingWindow=" + mContainer.startingWindow
94 + " startingView=" + mContainer.startingSurface);
Jorim Jaggi553cec62017-01-13 13:00:42 +010095 if (mContainer == null) {
96 return;
97 }
Jorim Jaggi02886a82016-12-06 09:10:06 -080098 if (mContainer.startingWindow != null) {
99 surface = mContainer.startingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800100 mContainer.startingData = null;
101 mContainer.startingSurface = null;
102 mContainer.startingWindow = null;
103 mContainer.startingDisplayed = false;
104 }
105 }
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100106 if (surface != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800107 try {
108 surface.remove();
109 } catch (Exception e) {
110 Slog.w(TAG_WM, "Exception when removing starting window", e);
111 }
112 }
113 };
114
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800115 private final Runnable mAddStartingWindow = () -> {
116 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100117 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800118
119 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100120 if (mContainer == null) {
121 return;
122 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800123 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100124 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800125 }
126
127 if (startingData == null) {
128 // Animation has been canceled... do nothing.
129 return;
130 }
131
132 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100133 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800134
Jorim Jaggi02886a82016-12-06 09:10:06 -0800135 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800136 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100137 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800138 } catch (Exception e) {
139 Slog.w(TAG_WM, "Exception when adding starting window", e);
140 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800141 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800142 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800143 synchronized(mWindowMap) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100144 if (container.removed || container.startingData == null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800145 // If the window was successfully added, then
146 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100147 if (container.startingWindow != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800148 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100149 "Aborted starting " + container
150 + ": removed=" + container.removed
151 + " startingData=" + container.startingData);
152 container.startingWindow = null;
153 container.startingData = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800154 abort = true;
155 }
156 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100157 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800158 }
159 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
160 "Added starting " + mContainer
161 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100162 + container.startingWindow + " startingView="
163 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800164 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800165 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100166 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800167 }
168 }
169 };
170
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800171 public AppWindowContainerController(TaskWindowContainerController taskController,
172 IApplicationToken token, AppWindowContainerListener listener, int index,
173 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800174 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
175 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800176 this(taskController, token, listener, index, requestedOrientation, fullscreen,
177 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800178 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
179 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
180 WindowManagerService.getInstance());
181 }
182
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800183 public AppWindowContainerController(TaskWindowContainerController taskController,
184 IApplicationToken token, AppWindowContainerListener listener, int index,
185 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800186 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
187 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
188 WindowManagerService service) {
189 super(listener, service);
Jorim Jaggi9bafc712017-01-19 17:28:30 +0100190 mHandler = new Handler(service.mH.getLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800191 mToken = token;
192 synchronized(mWindowMap) {
193 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
194 if (atoken != null) {
195 // TODO: Should this throw an exception instead?
196 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
197 return;
198 }
199
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800200 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800201 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800202 throw new IllegalArgumentException("AppWindowContainerController: invalid "
203 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800204 }
205
Winson Chung30480042017-01-26 10:55:34 -0800206 atoken = createAppWindow(mService, token, voiceInteraction, task.getDisplayContent(),
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800207 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
208 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
209 alwaysFocusable, this);
210 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800211 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800212 task.addChild(atoken, index);
213 }
214 }
215
Winson Chung30480042017-01-26 10:55:34 -0800216 @VisibleForTesting
217 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token,
218 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos,
219 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation,
220 int rotationAnimationHint, int configChanges, boolean launchTaskBehind,
221 boolean alwaysFocusable, AppWindowContainerController controller) {
222 return new AppWindowToken(service, token, voiceInteraction, dc,
223 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation,
224 rotationAnimationHint, configChanges, launchTaskBehind, alwaysFocusable,
225 controller);
226 }
227
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800228 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800229 synchronized(mWindowMap) {
230 final DisplayContent dc = mRoot.getDisplayContent(displayId);
231 if (dc == null) {
232 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
233 + mToken + " from non-existing displayId=" + displayId);
234 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800235 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800236 dc.removeAppToken(mToken.asBinder());
237 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800238 }
239 }
240
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800241 @Override
242 public void removeContainer() {
243 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800244 }
245
Winson Chung30480042017-01-26 10:55:34 -0800246 public void reparent(TaskWindowContainerController taskController, int position) {
247 synchronized (mWindowMap) {
248 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM, "reparent: moving app token=" + mToken
249 + " to task=" + taskController + " at " + position);
250 if (mContainer == null) {
251 if (DEBUG_ADD_REMOVE) Slog.i(TAG_WM,
252 "reparent: could not find app token=" + mToken);
253 return;
254 }
255 final Task task = taskController.mContainer;
256 if (task == null) {
257 throw new IllegalArgumentException("reparent: could not find task="
258 + taskController);
259 }
260 mContainer.reparent(task, position);
261 mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
262 }
263 }
264
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800265 public Configuration setOrientation(int requestedOrientation, int displayId,
266 Configuration displayConfig, boolean freezeScreenIfNeeded) {
267 synchronized(mWindowMap) {
268 if (mContainer == null) {
269 Slog.w(TAG_WM,
270 "Attempted to set orientation of non-existing app token: " + mToken);
271 return null;
272 }
273
274 mContainer.setOrientation(requestedOrientation);
275
276 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
277 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
278
279 }
280 }
281
282 public int getOrientation() {
283 synchronized(mWindowMap) {
284 if (mContainer == null) {
285 return SCREEN_ORIENTATION_UNSPECIFIED;
286 }
287
288 return mContainer.getOrientationIgnoreVisibility();
289 }
290 }
291
292 public void setVisibility(boolean visible) {
293 synchronized(mWindowMap) {
294 if (mContainer == null) {
295 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
296 + mToken);
297 return;
298 }
299
300 final AppWindowToken wtoken = mContainer;
301
302 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
303 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
304 + " hidden=" + wtoken.hidden + " hiddenRequested="
305 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
306
307 mService.mOpeningApps.remove(wtoken);
308 mService.mClosingApps.remove(wtoken);
309 wtoken.waitingToShow = false;
310 wtoken.hiddenRequested = !visible;
311
312 if (!visible) {
313 // If the app is dead while it was visible, we kept its dead window on screen.
314 // Now that the app is going invisible, we can remove it. It will be restarted
315 // if made visible again.
316 wtoken.removeDeadWindows();
317 wtoken.setVisibleBeforeClientHidden();
318 } else {
319 if (!mService.mAppTransition.isTransitionSet()
320 && mService.mAppTransition.isReady()) {
321 // Add the app mOpeningApps if transition is unset but ready. This means
322 // we're doing a screen freeze, and the unfreeze will wait for all opening
323 // apps to be ready.
324 mService.mOpeningApps.add(wtoken);
325 }
326 wtoken.startingMoved = false;
327 // If the token is currently hidden (should be the common case), or has been
328 // stopped, then we need to set up to wait for its windows to be ready.
329 if (wtoken.hidden || wtoken.mAppStopped) {
330 wtoken.clearAllDrawn();
331
332 // If the app was already visible, don't reset the waitingToShow state.
333 if (wtoken.hidden) {
334 wtoken.waitingToShow = true;
335 }
336
337 if (wtoken.clientHidden) {
338 // In the case where we are making an app visible
339 // but holding off for a transition, we still need
340 // to tell the client to make its windows visible so
341 // they get drawn. Otherwise, we will wait on
342 // performing the transition until all windows have
343 // been drawn, they never will be, and we are sad.
344 wtoken.clientHidden = false;
345 wtoken.sendAppVisibilityToClients();
346 }
347 }
348 wtoken.requestUpdateWallpaperIfNeeded();
349
350 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
351 wtoken.mAppStopped = false;
352 }
353
354 // If we are preparing an app transition, then delay changing
355 // the visibility of this token until we execute that transition.
356 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
357 // A dummy animation is a placeholder animation which informs others that an
358 // animation is going on (in this case an application transition). If the animation
359 // was transferred from another application/animator, no dummy animator should be
360 // created since an animation is already in progress.
361 if (wtoken.mAppAnimator.usingTransferredAnimation
362 && wtoken.mAppAnimator.animation == null) {
363 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
364 + ", using null transferred animation!");
365 }
366 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
367 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
368 if (DEBUG_APP_TRANSITIONS) Slog.v(
369 TAG_WM, "Setting dummy animation on: " + wtoken);
370 wtoken.mAppAnimator.setDummyAnimation();
371 }
372 wtoken.inPendingTransaction = true;
373 if (visible) {
374 mService.mOpeningApps.add(wtoken);
375 wtoken.mEnteringAnimation = true;
376 } else {
377 mService.mClosingApps.add(wtoken);
378 wtoken.mEnteringAnimation = false;
379 }
380 if (mService.mAppTransition.getAppTransition()
381 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
382 // We're launchingBehind, add the launching activity to mOpeningApps.
383 final WindowState win =
384 mService.getDefaultDisplayContentLocked().findFocusedWindow();
385 if (win != null) {
386 final AppWindowToken focusedToken = win.mAppToken;
387 if (focusedToken != null) {
388 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
389 + " adding " + focusedToken + " to mOpeningApps");
390 // Force animation to be loaded.
391 focusedToken.hidden = true;
392 mService.mOpeningApps.add(focusedToken);
393 }
394 }
395 }
396 return;
397 }
398
399 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
400 wtoken.updateReportedVisibilityLocked();
401 }
402 }
403
404 /**
405 * Notifies that we launched an app that might be visible or not visible depending on what kind
406 * of Keyguard flags it's going to set on its windows.
407 */
408 public void notifyUnknownVisibilityLaunched() {
409 synchronized(mWindowMap) {
410 if (mContainer != null) {
411 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
412 }
413 }
414 }
415
416 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
417 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800418 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800419 synchronized(mWindowMap) {
420 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
421 + " pkg=" + pkg + " transferFrom=" + transferFrom);
422
423 if (mContainer == null) {
424 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
425 return false;
426 }
427
428 // If the display is frozen, we won't do anything until the actual window is
429 // displayed so there is no reason to put in the starting window.
430 if (!mService.okToDisplay()) {
431 return false;
432 }
433
434 if (mContainer.startingData != null) {
435 return false;
436 }
437
Jorim Jaggi02886a82016-12-06 09:10:06 -0800438 final int type = getStartingWindowType(newTask, taskSwitch, processRunning);
439
440 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
441 return createSnapshot();
442 }
443
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800444 // If this is a translucent window, then don't show a starting window -- the current
445 // effect (a full-screen opaque starting window that fades away to the real contents
446 // when it is ready) does not work for this.
447 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
448 + Integer.toHexString(theme));
449 if (theme != 0) {
450 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
451 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
452 if (ent == null) {
453 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
454 // see that.
455 return false;
456 }
457 final boolean windowIsTranslucent = ent.array.getBoolean(
458 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
459 final boolean windowIsFloating = ent.array.getBoolean(
460 com.android.internal.R.styleable.Window_windowIsFloating, false);
461 final boolean windowShowWallpaper = ent.array.getBoolean(
462 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
463 final boolean windowDisableStarting = ent.array.getBoolean(
464 com.android.internal.R.styleable.Window_windowDisablePreview, false);
465 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
466 + " Floating=" + windowIsFloating
467 + " ShowWallpaper=" + windowShowWallpaper);
468 if (windowIsTranslucent) {
469 return false;
470 }
471 if (windowIsFloating || windowDisableStarting) {
472 return false;
473 }
474 if (windowShowWallpaper) {
475 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
476 == null) {
477 // If this theme is requesting a wallpaper, and the wallpaper
478 // is not currently visible, then this effectively serves as
479 // an opaque window and our starting window transition animation
480 // can still work. We just need to make sure the starting window
481 // is also showing the wallpaper.
482 windowFlags |= FLAG_SHOW_WALLPAPER;
483 } else {
484 return false;
485 }
486 }
487 }
488
489 if (mContainer.transferStartingWindow(transferFrom)) {
490 return true;
491 }
492
Jorim Jaggi02886a82016-12-06 09:10:06 -0800493 // There is no existing starting window, and we don't want to create a splash screen, so
494 // that's it!
495 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800496 return false;
497 }
498
499 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100500 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800501 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
502 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800503 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800504 }
505 return true;
506 }
507
Jorim Jaggi02886a82016-12-06 09:10:06 -0800508 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning) {
509 if (newTask || !processRunning) {
510 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
511 } else if (taskSwitch) {
512 return STARTING_WINDOW_TYPE_SNAPSHOT;
513 } else {
514 return STARTING_WINDOW_TYPE_NONE;
515 }
516 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800517
Jorim Jaggi02886a82016-12-06 09:10:06 -0800518 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800519 // Note: we really want to do sendMessageAtFrontOfQueue() because we
520 // want to process the message ASAP, before any other queued
521 // messages.
522 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
523 mHandler.postAtFrontOfQueue(mAddStartingWindow);
524 }
525
Jorim Jaggi02886a82016-12-06 09:10:06 -0800526 private boolean createSnapshot() {
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100527 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
Jorim Jaggi7361bab2017-01-16 17:17:58 +0100528 mContainer.mTask.mTaskId, mContainer.mTask.mUserId, false /* restoreFromDisk */);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800529
530 if (snapshot == null) {
531 return false;
532 }
533
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100534 mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800535 scheduleAddStartingWindow();
536 return true;
537 }
538
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800539 public void removeStartingWindow() {
540 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800541 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
542 // Already scheduled.
543 return;
544 }
545
546 if (mContainer.startingWindow == null) {
547 if (mContainer.startingData != null) {
548 // Starting window has not been added yet, but it is scheduled to be added.
549 // Go ahead and cancel the request.
550 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
551 "Clearing startingData for token=" + mContainer);
552 mContainer.startingData = null;
553 }
554 return;
555 }
556
557 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1)
558 + ": Schedule remove starting " + mContainer
559 + " startingWindow=" + mContainer.startingWindow);
560 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800561 }
562 }
563
564 public void pauseKeyDispatching() {
565 synchronized (mWindowMap) {
566 if (mContainer != null) {
567 mService.mInputMonitor.pauseDispatchingLw(mContainer);
568 }
569 }
570 }
571
572 public void resumeKeyDispatching() {
573 synchronized (mWindowMap) {
574 if (mContainer != null) {
575 mService.mInputMonitor.resumeDispatchingLw(mContainer);
576 }
577 }
578 }
579
580 public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
581 synchronized(mWindowMap) {
582 if (mContainer == null) {
583 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
584 return;
585 }
586 mContainer.notifyAppResumed(wasStopped, allowSavedSurface);
587 }
588 }
589
590 public void notifyAppStopped() {
591 synchronized(mWindowMap) {
592 if (mContainer == null) {
593 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
594 + mToken);
595 return;
596 }
597 mContainer.notifyAppStopped();
598 }
599 }
600
601 public void startFreezingScreen(int configChanges) {
602 synchronized(mWindowMap) {
603 if (configChanges == 0 && mService.okToDisplay()) {
604 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
605 return;
606 }
607
608 if (mContainer == null) {
609 Slog.w(TAG_WM,
610 "Attempted to freeze screen with non-existing app token: " + mContainer);
611 return;
612 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800613 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800614 }
615 }
616
617 public void stopFreezingScreen(boolean force) {
618 synchronized(mWindowMap) {
619 if (mContainer == null) {
620 return;
621 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800622 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
623 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
624 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800625 }
626 }
627
628 /**
629 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
630 * In portrait mode, it grabs the full screenshot.
631 *
632 * @param displayId the Display to take a screenshot of.
633 * @param width the width of the target bitmap
634 * @param height the height of the target bitmap
635 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
636 */
637 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
638 try {
639 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
640 final DisplayContent dc;
641 synchronized(mWindowMap) {
642 dc = mRoot.getDisplayContentOrCreate(displayId);
643 if (dc == null) {
644 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
645 + ": returning null. No Display for displayId=" + displayId);
646 return null;
647 }
648 }
649 return dc.screenshotApplications(mToken.asBinder(), width, height,
650 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100651 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800652 } finally {
653 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
654 }
655 }
656
657
658 void reportWindowsDrawn() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800659 mHandler.post(mOnWindowsDrawn);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800660 }
661
662 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800663 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800664 }
665
666 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800667 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800668 }
669
670 /** Calls directly into activity manager so window manager lock shouldn't held. */
671 boolean keyDispatchingTimedOut(String reason) {
672 return mListener != null && mListener.keyDispatchingTimedOut(reason);
673 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800674
675 @Override
676 public String toString() {
677 return "{AppWindowContainerController token=" + mToken + "}";
678 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800679}