blob: 34f675226a3b134308c47d7be30366c3ff57de88 [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
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080044import com.android.server.AttributeCache;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080045/**
46 * Controller for the app window token container. This is created by activity manager to link
47 * activity records to the app window token container they use in window manager.
48 *
49 * Test class: {@link AppWindowContainerControllerTests}
50 */
51public class AppWindowContainerController
52 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
53
Jorim Jaggi02886a82016-12-06 09:10:06 -080054 private static final int STARTING_WINDOW_TYPE_NONE = 0;
55 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1;
56 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2;
57
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080058 private final IApplicationToken mToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080059 private final Handler mHandler = new Handler(Looper.getMainLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080060
61 private final Runnable mOnWindowsDrawn = () -> {
62 if (mListener == null) {
63 return;
64 }
65 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
66 + AppWindowContainerController.this.mToken);
67 mListener.onWindowsDrawn();
68 };
69
70 private final Runnable mOnWindowsVisible = () -> {
71 if (mListener == null) {
72 return;
73 }
74 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
75 + AppWindowContainerController.this.mToken);
76 mListener.onWindowsVisible();
77 };
78
79 private final Runnable mOnWindowsGone = () -> {
80 if (mListener == null) {
81 return;
82 }
83 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
84 + AppWindowContainerController.this.mToken);
85 mListener.onWindowsGone();
86 };
87
Jorim Jaggi02886a82016-12-06 09:10:06 -080088 private final Runnable mRemoveStartingWindow = () -> {
89 StartingSurface surface = null;
Jorim Jaggi02886a82016-12-06 09:10:06 -080090 synchronized (mWindowMap) {
91 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting " + mContainer
92 + ": startingWindow=" + mContainer.startingWindow
93 + " startingView=" + mContainer.startingSurface);
Jorim Jaggi553cec62017-01-13 13:00:42 +010094 if (mContainer == null) {
95 return;
96 }
Jorim Jaggi02886a82016-12-06 09:10:06 -080097 if (mContainer.startingWindow != null) {
98 surface = mContainer.startingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -080099 mContainer.startingData = null;
100 mContainer.startingSurface = null;
101 mContainer.startingWindow = null;
102 mContainer.startingDisplayed = false;
103 }
104 }
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100105 if (surface != null) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800106 try {
107 surface.remove();
108 } catch (Exception e) {
109 Slog.w(TAG_WM, "Exception when removing starting window", e);
110 }
111 }
112 };
113
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800114 private final Runnable mAddStartingWindow = () -> {
115 final StartingData startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100116 final AppWindowToken container;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800117
118 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +0100119 if (mContainer == null) {
120 return;
121 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800122 startingData = mContainer.startingData;
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100123 container = mContainer;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800124 }
125
126 if (startingData == null) {
127 // Animation has been canceled... do nothing.
128 return;
129 }
130
131 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100132 + this + ": startingData=" + container.startingData);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800133
Jorim Jaggi02886a82016-12-06 09:10:06 -0800134 StartingSurface surface = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800135 try {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100136 surface = startingData.createStartingSurface(container);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800137 } catch (Exception e) {
138 Slog.w(TAG_WM, "Exception when adding starting window", e);
139 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800140 if (surface != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800141 boolean abort = false;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800142 synchronized(mWindowMap) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100143 if (container.removed || container.startingData == null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800144 // If the window was successfully added, then
145 // we need to remove it.
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100146 if (container.startingWindow != null) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800147 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100148 "Aborted starting " + container
149 + ": removed=" + container.removed
150 + " startingData=" + container.startingData);
151 container.startingWindow = null;
152 container.startingData = null;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800153 abort = true;
154 }
155 } else {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100156 container.startingSurface = surface;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800157 }
158 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
159 "Added starting " + mContainer
160 + ": startingWindow="
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100161 + container.startingWindow + " startingView="
162 + container.startingSurface);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800163 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800164 if (abort) {
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100165 surface.remove();
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800166 }
167 }
168 };
169
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800170 public AppWindowContainerController(TaskWindowContainerController taskController,
171 IApplicationToken token, AppWindowContainerListener listener, int index,
172 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800173 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
174 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800175 this(taskController, token, listener, index, requestedOrientation, fullscreen,
176 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800177 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
178 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
179 WindowManagerService.getInstance());
180 }
181
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800182 public AppWindowContainerController(TaskWindowContainerController taskController,
183 IApplicationToken token, AppWindowContainerListener listener, int index,
184 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800185 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
186 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
187 WindowManagerService service) {
188 super(listener, service);
189 mToken = token;
190 synchronized(mWindowMap) {
191 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
192 if (atoken != null) {
193 // TODO: Should this throw an exception instead?
194 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
195 return;
196 }
197
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800198 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800199 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800200 throw new IllegalArgumentException("AppWindowContainerController: invalid "
201 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800202 }
203
204 atoken = new AppWindowToken(mService, token, voiceInteraction, task.getDisplayContent(),
205 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
206 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
207 alwaysFocusable, this);
208 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800209 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800210 task.addChild(atoken, index);
211 }
212 }
213
214 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800215 synchronized(mWindowMap) {
216 final DisplayContent dc = mRoot.getDisplayContent(displayId);
217 if (dc == null) {
218 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
219 + mToken + " from non-existing displayId=" + displayId);
220 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800221 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800222 dc.removeAppToken(mToken.asBinder());
223 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800224 }
225 }
226
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800227 @Override
228 public void removeContainer() {
229 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800230 }
231
232 public Configuration setOrientation(int requestedOrientation, int displayId,
233 Configuration displayConfig, boolean freezeScreenIfNeeded) {
234 synchronized(mWindowMap) {
235 if (mContainer == null) {
236 Slog.w(TAG_WM,
237 "Attempted to set orientation of non-existing app token: " + mToken);
238 return null;
239 }
240
241 mContainer.setOrientation(requestedOrientation);
242
243 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
244 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
245
246 }
247 }
248
249 public int getOrientation() {
250 synchronized(mWindowMap) {
251 if (mContainer == null) {
252 return SCREEN_ORIENTATION_UNSPECIFIED;
253 }
254
255 return mContainer.getOrientationIgnoreVisibility();
256 }
257 }
258
259 public void setVisibility(boolean visible) {
260 synchronized(mWindowMap) {
261 if (mContainer == null) {
262 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
263 + mToken);
264 return;
265 }
266
267 final AppWindowToken wtoken = mContainer;
268
269 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
270 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
271 + " hidden=" + wtoken.hidden + " hiddenRequested="
272 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
273
274 mService.mOpeningApps.remove(wtoken);
275 mService.mClosingApps.remove(wtoken);
276 wtoken.waitingToShow = false;
277 wtoken.hiddenRequested = !visible;
278
279 if (!visible) {
280 // If the app is dead while it was visible, we kept its dead window on screen.
281 // Now that the app is going invisible, we can remove it. It will be restarted
282 // if made visible again.
283 wtoken.removeDeadWindows();
284 wtoken.setVisibleBeforeClientHidden();
285 } else {
286 if (!mService.mAppTransition.isTransitionSet()
287 && mService.mAppTransition.isReady()) {
288 // Add the app mOpeningApps if transition is unset but ready. This means
289 // we're doing a screen freeze, and the unfreeze will wait for all opening
290 // apps to be ready.
291 mService.mOpeningApps.add(wtoken);
292 }
293 wtoken.startingMoved = false;
294 // If the token is currently hidden (should be the common case), or has been
295 // stopped, then we need to set up to wait for its windows to be ready.
296 if (wtoken.hidden || wtoken.mAppStopped) {
297 wtoken.clearAllDrawn();
298
299 // If the app was already visible, don't reset the waitingToShow state.
300 if (wtoken.hidden) {
301 wtoken.waitingToShow = true;
302 }
303
304 if (wtoken.clientHidden) {
305 // In the case where we are making an app visible
306 // but holding off for a transition, we still need
307 // to tell the client to make its windows visible so
308 // they get drawn. Otherwise, we will wait on
309 // performing the transition until all windows have
310 // been drawn, they never will be, and we are sad.
311 wtoken.clientHidden = false;
312 wtoken.sendAppVisibilityToClients();
313 }
314 }
315 wtoken.requestUpdateWallpaperIfNeeded();
316
317 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
318 wtoken.mAppStopped = false;
319 }
320
321 // If we are preparing an app transition, then delay changing
322 // the visibility of this token until we execute that transition.
323 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
324 // A dummy animation is a placeholder animation which informs others that an
325 // animation is going on (in this case an application transition). If the animation
326 // was transferred from another application/animator, no dummy animator should be
327 // created since an animation is already in progress.
328 if (wtoken.mAppAnimator.usingTransferredAnimation
329 && wtoken.mAppAnimator.animation == null) {
330 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
331 + ", using null transferred animation!");
332 }
333 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
334 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
335 if (DEBUG_APP_TRANSITIONS) Slog.v(
336 TAG_WM, "Setting dummy animation on: " + wtoken);
337 wtoken.mAppAnimator.setDummyAnimation();
338 }
339 wtoken.inPendingTransaction = true;
340 if (visible) {
341 mService.mOpeningApps.add(wtoken);
342 wtoken.mEnteringAnimation = true;
343 } else {
344 mService.mClosingApps.add(wtoken);
345 wtoken.mEnteringAnimation = false;
346 }
347 if (mService.mAppTransition.getAppTransition()
348 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
349 // We're launchingBehind, add the launching activity to mOpeningApps.
350 final WindowState win =
351 mService.getDefaultDisplayContentLocked().findFocusedWindow();
352 if (win != null) {
353 final AppWindowToken focusedToken = win.mAppToken;
354 if (focusedToken != null) {
355 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
356 + " adding " + focusedToken + " to mOpeningApps");
357 // Force animation to be loaded.
358 focusedToken.hidden = true;
359 mService.mOpeningApps.add(focusedToken);
360 }
361 }
362 }
363 return;
364 }
365
366 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
367 wtoken.updateReportedVisibilityLocked();
368 }
369 }
370
371 /**
372 * Notifies that we launched an app that might be visible or not visible depending on what kind
373 * of Keyguard flags it's going to set on its windows.
374 */
375 public void notifyUnknownVisibilityLaunched() {
376 synchronized(mWindowMap) {
377 if (mContainer != null) {
378 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
379 }
380 }
381 }
382
383 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
384 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800385 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800386 synchronized(mWindowMap) {
387 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
388 + " pkg=" + pkg + " transferFrom=" + transferFrom);
389
390 if (mContainer == null) {
391 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
392 return false;
393 }
394
395 // If the display is frozen, we won't do anything until the actual window is
396 // displayed so there is no reason to put in the starting window.
397 if (!mService.okToDisplay()) {
398 return false;
399 }
400
401 if (mContainer.startingData != null) {
402 return false;
403 }
404
Jorim Jaggi02886a82016-12-06 09:10:06 -0800405 final int type = getStartingWindowType(newTask, taskSwitch, processRunning);
406
407 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) {
408 return createSnapshot();
409 }
410
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800411 // If this is a translucent window, then don't show a starting window -- the current
412 // effect (a full-screen opaque starting window that fades away to the real contents
413 // when it is ready) does not work for this.
414 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
415 + Integer.toHexString(theme));
416 if (theme != 0) {
417 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
418 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
419 if (ent == null) {
420 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
421 // see that.
422 return false;
423 }
424 final boolean windowIsTranslucent = ent.array.getBoolean(
425 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
426 final boolean windowIsFloating = ent.array.getBoolean(
427 com.android.internal.R.styleable.Window_windowIsFloating, false);
428 final boolean windowShowWallpaper = ent.array.getBoolean(
429 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
430 final boolean windowDisableStarting = ent.array.getBoolean(
431 com.android.internal.R.styleable.Window_windowDisablePreview, false);
432 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
433 + " Floating=" + windowIsFloating
434 + " ShowWallpaper=" + windowShowWallpaper);
435 if (windowIsTranslucent) {
436 return false;
437 }
438 if (windowIsFloating || windowDisableStarting) {
439 return false;
440 }
441 if (windowShowWallpaper) {
442 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
443 == null) {
444 // If this theme is requesting a wallpaper, and the wallpaper
445 // is not currently visible, then this effectively serves as
446 // an opaque window and our starting window transition animation
447 // can still work. We just need to make sure the starting window
448 // is also showing the wallpaper.
449 windowFlags |= FLAG_SHOW_WALLPAPER;
450 } else {
451 return false;
452 }
453 }
454 }
455
456 if (mContainer.transferStartingWindow(transferFrom)) {
457 return true;
458 }
459
Jorim Jaggi02886a82016-12-06 09:10:06 -0800460 // There is no existing starting window, and we don't want to create a splash screen, so
461 // that's it!
462 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800463 return false;
464 }
465
466 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100467 mContainer.startingData = new SplashScreenStartingData(mService, pkg, theme,
Jorim Jaggi02886a82016-12-06 09:10:06 -0800468 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
469 mContainer.getMergedOverrideConfiguration());
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800470 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800471 }
472 return true;
473 }
474
Jorim Jaggi02886a82016-12-06 09:10:06 -0800475 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning) {
476 if (newTask || !processRunning) {
477 return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
478 } else if (taskSwitch) {
479 return STARTING_WINDOW_TYPE_SNAPSHOT;
480 } else {
481 return STARTING_WINDOW_TYPE_NONE;
482 }
483 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800484
Jorim Jaggi02886a82016-12-06 09:10:06 -0800485 void scheduleAddStartingWindow() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800486 // Note: we really want to do sendMessageAtFrontOfQueue() because we
487 // want to process the message ASAP, before any other queued
488 // messages.
489 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
490 mHandler.postAtFrontOfQueue(mAddStartingWindow);
491 }
492
Jorim Jaggi02886a82016-12-06 09:10:06 -0800493 private boolean createSnapshot() {
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100494 final TaskSnapshot snapshot = mService.mTaskSnapshotController.getSnapshot(
Jorim Jaggi02886a82016-12-06 09:10:06 -0800495 mContainer.mTask);
496
497 if (snapshot == null) {
498 return false;
499 }
500
Jorim Jaggie09fc6b2017-01-19 15:33:36 +0100501 mContainer.startingData = new SnapshotStartingData(mService, snapshot.getSnapshot());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800502 scheduleAddStartingWindow();
503 return true;
504 }
505
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800506 public void removeStartingWindow() {
507 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800508 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
509 // Already scheduled.
510 return;
511 }
512
513 if (mContainer.startingWindow == null) {
514 if (mContainer.startingData != null) {
515 // Starting window has not been added yet, but it is scheduled to be added.
516 // Go ahead and cancel the request.
517 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
518 "Clearing startingData for token=" + mContainer);
519 mContainer.startingData = null;
520 }
521 return;
522 }
523
524 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1)
525 + ": Schedule remove starting " + mContainer
526 + " startingWindow=" + mContainer.startingWindow);
527 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800528 }
529 }
530
531 public void pauseKeyDispatching() {
532 synchronized (mWindowMap) {
533 if (mContainer != null) {
534 mService.mInputMonitor.pauseDispatchingLw(mContainer);
535 }
536 }
537 }
538
539 public void resumeKeyDispatching() {
540 synchronized (mWindowMap) {
541 if (mContainer != null) {
542 mService.mInputMonitor.resumeDispatchingLw(mContainer);
543 }
544 }
545 }
546
547 public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
548 synchronized(mWindowMap) {
549 if (mContainer == null) {
550 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
551 return;
552 }
553 mContainer.notifyAppResumed(wasStopped, allowSavedSurface);
554 }
555 }
556
557 public void notifyAppStopped() {
558 synchronized(mWindowMap) {
559 if (mContainer == null) {
560 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
561 + mToken);
562 return;
563 }
564 mContainer.notifyAppStopped();
565 }
566 }
567
568 public void startFreezingScreen(int configChanges) {
569 synchronized(mWindowMap) {
570 if (configChanges == 0 && mService.okToDisplay()) {
571 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
572 return;
573 }
574
575 if (mContainer == null) {
576 Slog.w(TAG_WM,
577 "Attempted to freeze screen with non-existing app token: " + mContainer);
578 return;
579 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800580 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800581 }
582 }
583
584 public void stopFreezingScreen(boolean force) {
585 synchronized(mWindowMap) {
586 if (mContainer == null) {
587 return;
588 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800589 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
590 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
591 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800592 }
593 }
594
595 /**
596 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
597 * In portrait mode, it grabs the full screenshot.
598 *
599 * @param displayId the Display to take a screenshot of.
600 * @param width the width of the target bitmap
601 * @param height the height of the target bitmap
602 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
603 */
604 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
605 try {
606 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
607 final DisplayContent dc;
608 synchronized(mWindowMap) {
609 dc = mRoot.getDisplayContentOrCreate(displayId);
610 if (dc == null) {
611 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
612 + ": returning null. No Display for displayId=" + displayId);
613 return null;
614 }
615 }
616 return dc.screenshotApplications(mToken.asBinder(), width, height,
617 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
Jorim Jaggi6a7a8592017-01-12 00:44:33 +0100618 false /* wallpaperOnly */, false /* includeDecor */);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800619 } finally {
620 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
621 }
622 }
623
624
625 void reportWindowsDrawn() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800626 mHandler.post(mOnWindowsDrawn);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800627 }
628
629 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800630 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800631 }
632
633 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800634 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800635 }
636
637 /** Calls directly into activity manager so window manager lock shouldn't held. */
638 boolean keyDispatchingTimedOut(String reason) {
639 return mListener != null && mListener.keyDispatchingTimedOut(reason);
640 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800641
642 @Override
643 public String toString() {
644 return "{AppWindowContainerController token=" + mToken + "}";
645 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800646}