blob: d2f604d671321f6cf870226bf99a3dec90644df4 [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
31import android.content.res.CompatibilityInfo;
32import android.content.res.Configuration;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080033import android.graphics.Bitmap;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080034import android.os.Debug;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080035import android.os.Handler;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080036import android.os.IBinder;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080037import android.os.Looper;
38import android.os.Trace;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080039import android.util.Slog;
40import android.view.IApplicationToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080041import android.view.WindowManagerPolicy.StartingSurface;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080042
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080043import com.android.server.AttributeCache;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080044/**
45 * Controller for the app window token container. This is created by activity manager to link
46 * activity records to the app window token container they use in window manager.
47 *
48 * Test class: {@link AppWindowContainerControllerTests}
49 */
50public class AppWindowContainerController
51 extends WindowContainerController<AppWindowToken, AppWindowContainerListener> {
52
53 private final IApplicationToken mToken;
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080054 private final Handler mHandler = new Handler(Looper.getMainLooper());
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -080055
56 private final Runnable mOnWindowsDrawn = () -> {
57 if (mListener == null) {
58 return;
59 }
60 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting drawn in "
61 + AppWindowContainerController.this.mToken);
62 mListener.onWindowsDrawn();
63 };
64
65 private final Runnable mOnWindowsVisible = () -> {
66 if (mListener == null) {
67 return;
68 }
69 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in "
70 + AppWindowContainerController.this.mToken);
71 mListener.onWindowsVisible();
72 };
73
74 private final Runnable mOnWindowsGone = () -> {
75 if (mListener == null) {
76 return;
77 }
78 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in "
79 + AppWindowContainerController.this.mToken);
80 mListener.onWindowsGone();
81 };
82
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080083 private final Runnable mAddStartingWindow = () -> {
84 final StartingData startingData;
85 final Configuration mergedOverrideConfiguration;
86
87 synchronized (mWindowMap) {
Jorim Jaggi73f88202017-01-12 13:54:40 +010088 if (mContainer == null) {
89 return;
90 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -080091 startingData = mContainer.startingData;
92 mergedOverrideConfiguration = mContainer.getMergedOverrideConfiguration();
93 }
94
95 if (startingData == null) {
96 // Animation has been canceled... do nothing.
97 return;
98 }
99
100 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
101 + this + ": pkg=" + mContainer.startingData.pkg);
102
103 StartingSurface contents = null;
104 try {
105 contents = mService.mPolicy.addSplashScreen(mContainer.token, startingData.pkg,
106 startingData.theme, startingData.compatInfo, startingData.nonLocalizedLabel,
107 startingData.labelRes, startingData.icon, startingData.logo,
108 startingData.windowFlags, mergedOverrideConfiguration);
109 } catch (Exception e) {
110 Slog.w(TAG_WM, "Exception when adding starting window", e);
111 }
112 if (contents != null) {
113 boolean abort = false;
114
115 synchronized(mWindowMap) {
116 if (mContainer.removed || mContainer.startingData == null) {
117 // If the window was successfully added, then
118 // we need to remove it.
119 if (mContainer.startingWindow != null) {
120 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
121 "Aborted starting " + mContainer
122 + ": removed=" + mContainer.removed
123 + " startingData=" + mContainer.startingData);
124 mContainer.startingWindow = null;
125 mContainer.startingData = null;
126 abort = true;
127 }
128 } else {
129 mContainer.startingSurface = contents;
130 }
131 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
132 "Added starting " + mContainer
133 + ": startingWindow="
134 + mContainer.startingWindow + " startingView="
135 + mContainer.startingSurface);
136 }
137
138 if (abort) {
139 try {
140 mService.mPolicy.removeSplashScreen(mContainer.token, contents);
141 } catch (Exception e) {
142 Slog.w(TAG_WM, "Exception when removing starting window", e);
143 }
144 }
145 }
146 };
147
148 private final Runnable mRemoveStartingWindow = () -> {
149 IBinder token = null;
150 StartingSurface contents = null;
151 synchronized (mWindowMap) {
152 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting "
153 + mContainer + ": startingWindow="
154 + mContainer.startingWindow + " startingView="
155 + mContainer.startingSurface);
Jorim Jaggi73f88202017-01-12 13:54:40 +0100156 if (mContainer == null) {
157 return;
158 }
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800159 if (mContainer.startingWindow != null) {
160 contents = mContainer.startingSurface;
161 token = mContainer.token;
162 mContainer.startingData = null;
163 mContainer.startingSurface = null;
164 mContainer.startingWindow = null;
165 mContainer.startingDisplayed = false;
166 }
167 }
168 if (contents != null) {
169 try {
170 mService.mPolicy.removeSplashScreen(token, contents);
171 } catch (Exception e) {
172 Slog.w(TAG_WM, "Exception when removing starting window", e);
173 }
174 }
175 };
176
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800177 public AppWindowContainerController(TaskWindowContainerController taskController,
178 IApplicationToken token, AppWindowContainerListener listener, int index,
179 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800180 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
181 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800182 this(taskController, token, listener, index, requestedOrientation, fullscreen,
183 showForAllUsers,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800184 configChanges, voiceInteraction, launchTaskBehind, alwaysFocusable,
185 targetSdkVersion, rotationAnimationHint, inputDispatchingTimeoutNanos,
186 WindowManagerService.getInstance());
187 }
188
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800189 public AppWindowContainerController(TaskWindowContainerController taskController,
190 IApplicationToken token, AppWindowContainerListener listener, int index,
191 int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int configChanges,
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800192 boolean voiceInteraction, boolean launchTaskBehind, boolean alwaysFocusable,
193 int targetSdkVersion, int rotationAnimationHint, long inputDispatchingTimeoutNanos,
194 WindowManagerService service) {
195 super(listener, service);
196 mToken = token;
197 synchronized(mWindowMap) {
198 AppWindowToken atoken = mRoot.getAppWindowToken(mToken.asBinder());
199 if (atoken != null) {
200 // TODO: Should this throw an exception instead?
201 Slog.w(TAG_WM, "Attempted to add existing app token: " + mToken);
202 return;
203 }
204
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800205 final Task task = taskController.mContainer;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800206 if (task == null) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800207 throw new IllegalArgumentException("AppWindowContainerController: invalid "
208 + " controller=" + taskController);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800209 }
210
211 atoken = new AppWindowToken(mService, token, voiceInteraction, task.getDisplayContent(),
212 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdkVersion,
213 requestedOrientation, rotationAnimationHint, configChanges, launchTaskBehind,
214 alwaysFocusable, this);
215 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800216 + " controller=" + taskController + " at " + index);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800217 task.addChild(atoken, index);
218 }
219 }
220
221 public void removeContainer(int displayId) {
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800222 synchronized(mWindowMap) {
223 final DisplayContent dc = mRoot.getDisplayContent(displayId);
224 if (dc == null) {
225 Slog.w(TAG_WM, "removeAppToken: Attempted to remove binder token: "
226 + mToken + " from non-existing displayId=" + displayId);
227 return;
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800228 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800229 dc.removeAppToken(mToken.asBinder());
230 super.removeContainer();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800231 }
232 }
233
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800234 @Override
235 public void removeContainer() {
236 throw new UnsupportedOperationException("Use removeContainer(displayId) instead.");
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800237 }
238
239 public Configuration setOrientation(int requestedOrientation, int displayId,
240 Configuration displayConfig, boolean freezeScreenIfNeeded) {
241 synchronized(mWindowMap) {
242 if (mContainer == null) {
243 Slog.w(TAG_WM,
244 "Attempted to set orientation of non-existing app token: " + mToken);
245 return null;
246 }
247
248 mContainer.setOrientation(requestedOrientation);
249
250 final IBinder binder = freezeScreenIfNeeded ? mToken.asBinder() : null;
251 return mService.updateOrientationFromAppTokens(displayConfig, binder, displayId);
252
253 }
254 }
255
256 public int getOrientation() {
257 synchronized(mWindowMap) {
258 if (mContainer == null) {
259 return SCREEN_ORIENTATION_UNSPECIFIED;
260 }
261
262 return mContainer.getOrientationIgnoreVisibility();
263 }
264 }
265
266 public void setVisibility(boolean visible) {
267 synchronized(mWindowMap) {
268 if (mContainer == null) {
269 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
270 + mToken);
271 return;
272 }
273
274 final AppWindowToken wtoken = mContainer;
275
276 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
277 + mToken + ", visible=" + visible + "): " + mService.mAppTransition
278 + " hidden=" + wtoken.hidden + " hiddenRequested="
279 + wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
280
281 mService.mOpeningApps.remove(wtoken);
282 mService.mClosingApps.remove(wtoken);
283 wtoken.waitingToShow = false;
284 wtoken.hiddenRequested = !visible;
285
286 if (!visible) {
287 // If the app is dead while it was visible, we kept its dead window on screen.
288 // Now that the app is going invisible, we can remove it. It will be restarted
289 // if made visible again.
290 wtoken.removeDeadWindows();
291 wtoken.setVisibleBeforeClientHidden();
292 } else {
293 if (!mService.mAppTransition.isTransitionSet()
294 && mService.mAppTransition.isReady()) {
295 // Add the app mOpeningApps if transition is unset but ready. This means
296 // we're doing a screen freeze, and the unfreeze will wait for all opening
297 // apps to be ready.
298 mService.mOpeningApps.add(wtoken);
299 }
300 wtoken.startingMoved = false;
301 // If the token is currently hidden (should be the common case), or has been
302 // stopped, then we need to set up to wait for its windows to be ready.
303 if (wtoken.hidden || wtoken.mAppStopped) {
304 wtoken.clearAllDrawn();
305
306 // If the app was already visible, don't reset the waitingToShow state.
307 if (wtoken.hidden) {
308 wtoken.waitingToShow = true;
309 }
310
311 if (wtoken.clientHidden) {
312 // In the case where we are making an app visible
313 // but holding off for a transition, we still need
314 // to tell the client to make its windows visible so
315 // they get drawn. Otherwise, we will wait on
316 // performing the transition until all windows have
317 // been drawn, they never will be, and we are sad.
318 wtoken.clientHidden = false;
319 wtoken.sendAppVisibilityToClients();
320 }
321 }
322 wtoken.requestUpdateWallpaperIfNeeded();
323
324 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "No longer Stopped: " + wtoken);
325 wtoken.mAppStopped = false;
326 }
327
328 // If we are preparing an app transition, then delay changing
329 // the visibility of this token until we execute that transition.
330 if (mService.okToDisplay() && mService.mAppTransition.isTransitionSet()) {
331 // A dummy animation is a placeholder animation which informs others that an
332 // animation is going on (in this case an application transition). If the animation
333 // was transferred from another application/animator, no dummy animator should be
334 // created since an animation is already in progress.
335 if (wtoken.mAppAnimator.usingTransferredAnimation
336 && wtoken.mAppAnimator.animation == null) {
337 Slog.wtf(TAG_WM, "Will NOT set dummy animation on: " + wtoken
338 + ", using null transferred animation!");
339 }
340 if (!wtoken.mAppAnimator.usingTransferredAnimation &&
341 (!wtoken.startingDisplayed || mService.mSkipAppTransitionAnimation)) {
342 if (DEBUG_APP_TRANSITIONS) Slog.v(
343 TAG_WM, "Setting dummy animation on: " + wtoken);
344 wtoken.mAppAnimator.setDummyAnimation();
345 }
346 wtoken.inPendingTransaction = true;
347 if (visible) {
348 mService.mOpeningApps.add(wtoken);
349 wtoken.mEnteringAnimation = true;
350 } else {
351 mService.mClosingApps.add(wtoken);
352 wtoken.mEnteringAnimation = false;
353 }
354 if (mService.mAppTransition.getAppTransition()
355 == AppTransition.TRANSIT_TASK_OPEN_BEHIND) {
356 // We're launchingBehind, add the launching activity to mOpeningApps.
357 final WindowState win =
358 mService.getDefaultDisplayContentLocked().findFocusedWindow();
359 if (win != null) {
360 final AppWindowToken focusedToken = win.mAppToken;
361 if (focusedToken != null) {
362 if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "TRANSIT_TASK_OPEN_BEHIND, "
363 + " adding " + focusedToken + " to mOpeningApps");
364 // Force animation to be loaded.
365 focusedToken.hidden = true;
366 mService.mOpeningApps.add(focusedToken);
367 }
368 }
369 }
370 return;
371 }
372
373 wtoken.setVisibility(null, visible, TRANSIT_UNSET, true, wtoken.mVoiceInteraction);
374 wtoken.updateReportedVisibilityLocked();
375 }
376 }
377
378 /**
379 * Notifies that we launched an app that might be visible or not visible depending on what kind
380 * of Keyguard flags it's going to set on its windows.
381 */
382 public void notifyUnknownVisibilityLaunched() {
383 synchronized(mWindowMap) {
384 if (mContainer != null) {
385 mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
386 }
387 }
388 }
389
390 public boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo,
391 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags,
392 IBinder transferFrom, boolean createIfNeeded) {
393 synchronized(mWindowMap) {
394 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "setAppStartingWindow: token=" + mToken
395 + " pkg=" + pkg + " transferFrom=" + transferFrom);
396
397 if (mContainer == null) {
398 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + mToken);
399 return false;
400 }
401
402 // If the display is frozen, we won't do anything until the actual window is
403 // displayed so there is no reason to put in the starting window.
404 if (!mService.okToDisplay()) {
405 return false;
406 }
407
408 if (mContainer.startingData != null) {
409 return false;
410 }
411
412 // If this is a translucent window, then don't show a starting window -- the current
413 // effect (a full-screen opaque starting window that fades away to the real contents
414 // when it is ready) does not work for this.
415 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Checking theme of starting window: 0x"
416 + Integer.toHexString(theme));
417 if (theme != 0) {
418 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
419 com.android.internal.R.styleable.Window, mService.mCurrentUserId);
420 if (ent == null) {
421 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't
422 // see that.
423 return false;
424 }
425 final boolean windowIsTranslucent = ent.array.getBoolean(
426 com.android.internal.R.styleable.Window_windowIsTranslucent, false);
427 final boolean windowIsFloating = ent.array.getBoolean(
428 com.android.internal.R.styleable.Window_windowIsFloating, false);
429 final boolean windowShowWallpaper = ent.array.getBoolean(
430 com.android.internal.R.styleable.Window_windowShowWallpaper, false);
431 final boolean windowDisableStarting = ent.array.getBoolean(
432 com.android.internal.R.styleable.Window_windowDisablePreview, false);
433 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Translucent=" + windowIsTranslucent
434 + " Floating=" + windowIsFloating
435 + " ShowWallpaper=" + windowShowWallpaper);
436 if (windowIsTranslucent) {
437 return false;
438 }
439 if (windowIsFloating || windowDisableStarting) {
440 return false;
441 }
442 if (windowShowWallpaper) {
443 if (mContainer.getDisplayContent().mWallpaperController.getWallpaperTarget()
444 == null) {
445 // If this theme is requesting a wallpaper, and the wallpaper
446 // is not currently visible, then this effectively serves as
447 // an opaque window and our starting window transition animation
448 // can still work. We just need to make sure the starting window
449 // is also showing the wallpaper.
450 windowFlags |= FLAG_SHOW_WALLPAPER;
451 } else {
452 return false;
453 }
454 }
455 }
456
457 if (mContainer.transferStartingWindow(transferFrom)) {
458 return true;
459 }
460
461 // There is no existing starting window, and the caller doesn't
462 // want us to create one, so that's it!
463 if (!createIfNeeded) {
464 return false;
465 }
466
467 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
468 mContainer.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
469 labelRes, icon, logo, windowFlags);
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800470 scheduleAddStartingWindow();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800471 }
472 return true;
473 }
474
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800475 void scheduleAddStartingWindow() {
476
477 // Note: we really want to do sendMessageAtFrontOfQueue() because we
478 // want to process the message ASAP, before any other queued
479 // messages.
480 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Enqueueing ADD_STARTING");
481 mHandler.postAtFrontOfQueue(mAddStartingWindow);
482 }
483
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800484 public void removeStartingWindow() {
485 synchronized (mWindowMap) {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800486 if (mHandler.hasCallbacks(mRemoveStartingWindow)) {
487 // Already scheduled.
488 return;
489 }
490
491 if (mContainer.startingWindow == null) {
492 if (mContainer.startingData != null) {
493 // Starting window has not been added yet, but it is scheduled to be added.
494 // Go ahead and cancel the request.
495 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
496 "Clearing startingData for token=" + mContainer);
497 mContainer.startingData = null;
498 }
499 return;
500 }
501
502 if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, Debug.getCallers(1)
503 + ": Schedule remove starting " + mContainer
504 + " startingWindow=" + mContainer.startingWindow);
505 mHandler.post(mRemoveStartingWindow);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800506 }
507 }
508
509 public void pauseKeyDispatching() {
510 synchronized (mWindowMap) {
511 if (mContainer != null) {
512 mService.mInputMonitor.pauseDispatchingLw(mContainer);
513 }
514 }
515 }
516
517 public void resumeKeyDispatching() {
518 synchronized (mWindowMap) {
519 if (mContainer != null) {
520 mService.mInputMonitor.resumeDispatchingLw(mContainer);
521 }
522 }
523 }
524
525 public void notifyAppResumed(boolean wasStopped, boolean allowSavedSurface) {
526 synchronized(mWindowMap) {
527 if (mContainer == null) {
528 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + mToken);
529 return;
530 }
531 mContainer.notifyAppResumed(wasStopped, allowSavedSurface);
532 }
533 }
534
535 public void notifyAppStopped() {
536 synchronized(mWindowMap) {
537 if (mContainer == null) {
538 Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: "
539 + mToken);
540 return;
541 }
542 mContainer.notifyAppStopped();
543 }
544 }
545
546 public void startFreezingScreen(int configChanges) {
547 synchronized(mWindowMap) {
548 if (configChanges == 0 && mService.okToDisplay()) {
549 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + mToken);
550 return;
551 }
552
553 if (mContainer == null) {
554 Slog.w(TAG_WM,
555 "Attempted to freeze screen with non-existing app token: " + mContainer);
556 return;
557 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800558 mContainer.startFreezingScreen();
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800559 }
560 }
561
562 public void stopFreezingScreen(boolean force) {
563 synchronized(mWindowMap) {
564 if (mContainer == null) {
565 return;
566 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800567 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + mToken + ": hidden="
568 + mContainer.hidden + " freezing=" + mContainer.mAppAnimator.freezingScreen);
569 mContainer.stopFreezingScreen(true, force);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800570 }
571 }
572
573 /**
574 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
575 * In portrait mode, it grabs the full screenshot.
576 *
577 * @param displayId the Display to take a screenshot of.
578 * @param width the width of the target bitmap
579 * @param height the height of the target bitmap
580 * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
581 */
582 public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
583 try {
584 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
585 final DisplayContent dc;
586 synchronized(mWindowMap) {
587 dc = mRoot.getDisplayContentOrCreate(displayId);
588 if (dc == null) {
589 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
590 + ": returning null. No Display for displayId=" + displayId);
591 return null;
592 }
593 }
594 return dc.screenshotApplications(mToken.asBinder(), width, height,
595 false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
596 false /* wallpaperOnly */);
597 } finally {
598 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
599 }
600 }
601
602
603 void reportWindowsDrawn() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800604 mHandler.post(mOnWindowsDrawn);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800605 }
606
607 void reportWindowsVisible() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800608 mHandler.post(mOnWindowsVisible);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800609 }
610
611 void reportWindowsGone() {
Jorim Jaggiba41f4b2016-12-14 17:43:07 -0800612 mHandler.post(mOnWindowsGone);
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800613 }
614
615 /** Calls directly into activity manager so window manager lock shouldn't held. */
616 boolean keyDispatchingTimedOut(String reason) {
617 return mListener != null && mListener.keyDispatchingTimedOut(reason);
618 }
Wale Ogunwalee1fe7fa22016-12-15 18:27:00 -0800619
620 @Override
621 public String toString() {
622 return "{AppWindowContainerController token=" + mToken + "}";
623 }
Wale Ogunwale26c0dfe2016-12-14 14:42:30 -0800624}