blob: 733a2486215df1538e6f5d31c61c25306787849f [file] [log] [blame]
Jorim Jaggi02886a82016-12-06 09:10:06 -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
Matthew Ngcb7ac672017-07-21 17:27:42 -070019import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS;
20import static com.android.server.wm.TaskSnapshotPersister.REDUCED_SCALE;
chaviwfbe47df2017-11-10 16:14:49 -080021import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
Winson Chung3e13ef82017-06-29 12:41:14 -070022import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
23import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
24
Jorim Jaggi02886a82016-12-06 09:10:06 -080025import android.annotation.Nullable;
Jorim Jaggi3d732602017-02-22 17:56:40 +010026import android.app.ActivityManager;
Jorim Jaggie2c77f92016-12-29 14:57:22 +010027import android.app.ActivityManager.TaskSnapshot;
Keyvan Amirie681cec2017-06-05 22:48:26 -070028import android.content.pm.PackageManager;
Jorim Jaggi6aead1c2017-05-23 15:07:44 +020029import android.graphics.Bitmap;
Jorim Jaggi02886a82016-12-06 09:10:06 -080030import android.graphics.GraphicBuffer;
Winson Chung02378b42018-06-04 16:40:09 -070031import android.graphics.PixelFormat;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020032import android.graphics.Rect;
Jorim Jaggif9084ec2017-01-16 13:16:59 +010033import android.os.Environment;
Jorim Jaggi51304d72017-05-17 17:25:32 +020034import android.os.Handler;
Jorim Jaggi02886a82016-12-06 09:10:06 -080035import android.util.ArraySet;
Winson Chung3e13ef82017-06-29 12:41:14 -070036import android.util.Slog;
Winson Chung91092762017-05-24 14:08:48 -070037import android.view.DisplayListCanvas;
38import android.view.RenderNode;
chaviwfbe47df2017-11-10 16:14:49 -080039import android.view.SurfaceControl;
Winson Chung91092762017-05-24 14:08:48 -070040import android.view.ThreadedRenderer;
Winson Chung173020c2018-05-04 15:36:47 -070041import android.view.View;
Jorim Jaggid635a4a2017-05-03 15:21:26 +020042import android.view.WindowManager.LayoutParams;
Guang Zhu09486a32017-06-06 03:27:44 +000043
Jorim Jaggi02886a82016-12-06 09:10:06 -080044import com.android.internal.annotations.VisibleForTesting;
Winson Chung51f42d22018-02-01 14:59:38 -080045import com.android.internal.graphics.ColorUtils;
Adrian Roose99bc052017-11-20 17:55:31 +010046import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
47import com.android.server.policy.WindowManagerPolicy.StartingSurface;
Jorim Jaggid635a4a2017-05-03 15:21:26 +020048import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
Jorim Jaggi817ebdd2018-03-26 15:46:01 +020049import com.android.server.wm.utils.InsetUtils;
Jorim Jaggi02886a82016-12-06 09:10:06 -080050
Adrian Roose99bc052017-11-20 17:55:31 +010051import com.google.android.collect.Sets;
52
Jorim Jaggi10abe2f2017-01-03 16:44:46 +010053import java.io.PrintWriter;
54
Jorim Jaggi02886a82016-12-06 09:10:06 -080055/**
56 * When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
57 * put it into our cache. Internally we use gralloc buffers to be able to draw them wherever we
58 * like without any copying.
59 * <p>
60 * System applications may retrieve a snapshot to represent the current state of a task, and draw
61 * them in their own process.
62 * <p>
63 * When we task becomes visible again, we show a starting window with the snapshot as the content to
64 * make app transitions more responsive.
65 * <p>
66 * To access this class, acquire the global window manager lock.
67 */
68class TaskSnapshotController {
Winson Chung3e13ef82017-06-29 12:41:14 -070069 private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotController" : TAG_WM;
Jorim Jaggi02886a82016-12-06 09:10:06 -080070
Jorim Jaggi8f4fe6e2017-03-14 18:21:40 +010071 /**
72 * Return value for {@link #getSnapshotMode}: We are allowed to take a real screenshot to be
73 * used as the snapshot.
74 */
75 @VisibleForTesting
76 static final int SNAPSHOT_MODE_REAL = 0;
77
78 /**
79 * Return value for {@link #getSnapshotMode}: We are not allowed to take a real screenshot but
80 * we should try to use the app theme to create a dummy representation of the app.
81 */
82 @VisibleForTesting
83 static final int SNAPSHOT_MODE_APP_THEME = 1;
84
85 /**
86 * Return value for {@link #getSnapshotMode}: We aren't allowed to take any snapshot.
87 */
88 @VisibleForTesting
89 static final int SNAPSHOT_MODE_NONE = 2;
90
Jorim Jaggi02886a82016-12-06 09:10:06 -080091 private final WindowManagerService mService;
Jorim Jaggi02886a82016-12-06 09:10:06 -080092
Jorim Jaggi7361bab2017-01-16 17:17:58 +010093 private final TaskSnapshotCache mCache;
Jorim Jaggif9084ec2017-01-16 13:16:59 +010094 private final TaskSnapshotPersister mPersister = new TaskSnapshotPersister(
95 Environment::getDataSystemCeDirectory);
96 private final TaskSnapshotLoader mLoader = new TaskSnapshotLoader(mPersister);
Winson Chung23aa7b12018-02-01 11:41:43 -080097 private final ArraySet<Task> mSkipClosingAppSnapshotTasks = new ArraySet<>();
Jorim Jaggi02886a82016-12-06 09:10:06 -080098 private final ArraySet<Task> mTmpTasks = new ArraySet<>();
Jorim Jaggi51304d72017-05-17 17:25:32 +020099 private final Handler mHandler = new Handler();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800100
chaviw23ee71c2017-12-18 11:29:41 -0800101 private final Rect mTmpRect = new Rect();
102
Keyvan Amirie681cec2017-06-05 22:48:26 -0700103 /**
104 * Flag indicating whether we are running on an Android TV device.
105 */
106 private final boolean mIsRunningOnTv;
107
Juho Haf5dd7cc2017-06-15 11:38:56 +0900108 /**
109 * Flag indicating whether we are running on an IoT device.
110 */
111 private final boolean mIsRunningOnIoT;
112
Matthew Ng95378192017-08-16 11:57:00 -0700113 /**
114 * Flag indicating whether we are running on an Android Wear device.
115 */
116 private final boolean mIsRunningOnWear;
117
Jorim Jaggi02886a82016-12-06 09:10:06 -0800118 TaskSnapshotController(WindowManagerService service) {
119 mService = service;
Jorim Jaggi7361bab2017-01-16 17:17:58 +0100120 mCache = new TaskSnapshotCache(mService, mLoader);
Keyvan Amirie681cec2017-06-05 22:48:26 -0700121 mIsRunningOnTv = mService.mContext.getPackageManager().hasSystemFeature(
122 PackageManager.FEATURE_LEANBACK);
Juho Haf5dd7cc2017-06-15 11:38:56 +0900123 mIsRunningOnIoT = mService.mContext.getPackageManager().hasSystemFeature(
124 PackageManager.FEATURE_EMBEDDED);
Matthew Ng95378192017-08-16 11:57:00 -0700125 mIsRunningOnWear = mService.mContext.getPackageManager().hasSystemFeature(
126 PackageManager.FEATURE_WATCH);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800127 }
128
Jorim Jaggif9084ec2017-01-16 13:16:59 +0100129 void systemReady() {
130 mPersister.start();
131 }
132
Jorim Jaggi02886a82016-12-06 09:10:06 -0800133 void onTransitionStarting() {
Jorim Jaggi8b702ed2017-01-20 16:59:03 +0100134 handleClosingApps(mService.mClosingApps);
135 }
136
Jorim Jaggi8b702ed2017-01-20 16:59:03 +0100137 /**
138 * Called when the visibility of an app changes outside of the regular app transition flow.
139 */
140 void notifyAppVisibilityChanged(AppWindowToken appWindowToken, boolean visible) {
Jorim Jaggi8b702ed2017-01-20 16:59:03 +0100141 if (!visible) {
142 handleClosingApps(Sets.newArraySet(appWindowToken));
143 }
144 }
145
146 private void handleClosingApps(ArraySet<AppWindowToken> closingApps) {
Keyvan Amirie681cec2017-06-05 22:48:26 -0700147 if (shouldDisableSnapshots()) {
Jorim Jaggi3d732602017-02-22 17:56:40 +0100148 return;
149 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800150
151 // We need to take a snapshot of the task if and only if all activities of the task are
152 // either closing or hidden.
Jorim Jaggi8b702ed2017-01-20 16:59:03 +0100153 getClosingTasks(closingApps, mTmpTasks);
Jorim Jaggi51304d72017-05-17 17:25:32 +0200154 snapshotTasks(mTmpTasks);
Winson Chung23aa7b12018-02-01 11:41:43 -0800155 mSkipClosingAppSnapshotTasks.clear();
Jorim Jaggi51304d72017-05-17 17:25:32 +0200156 }
157
Winson Chung23aa7b12018-02-01 11:41:43 -0800158 /**
159 * Adds the given {@param tasks} to the list of tasks which should not have their snapshots
160 * taken upon the next processing of the set of closing apps. The caller is responsible for
161 * calling {@link #snapshotTasks} to ensure that the task has an up-to-date snapshot.
162 */
163 @VisibleForTesting
164 void addSkipClosingAppSnapshotTasks(ArraySet<Task> tasks) {
165 mSkipClosingAppSnapshotTasks.addAll(tasks);
166 }
167
168 void snapshotTasks(ArraySet<Task> tasks) {
Jorim Jaggi51304d72017-05-17 17:25:32 +0200169 for (int i = tasks.size() - 1; i >= 0; i--) {
170 final Task task = tasks.valueAt(i);
Jorim Jaggi8f4fe6e2017-03-14 18:21:40 +0100171 final int mode = getSnapshotMode(task);
172 final TaskSnapshot snapshot;
173 switch (mode) {
174 case SNAPSHOT_MODE_NONE:
175 continue;
176 case SNAPSHOT_MODE_APP_THEME:
177 snapshot = drawAppThemeSnapshot(task);
178 break;
179 case SNAPSHOT_MODE_REAL:
180 snapshot = snapshotTask(task);
181 break;
182 default:
183 snapshot = null;
184 break;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800185 }
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100186 if (snapshot != null) {
Winson Chung3e13ef82017-06-29 12:41:14 -0700187 final GraphicBuffer buffer = snapshot.getSnapshot();
188 if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
189 buffer.destroy();
190 Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
191 + buffer.getHeight());
192 } else {
193 mCache.putSnapshot(task, snapshot);
194 mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
195 if (task.getController() != null) {
196 task.getController().reportSnapshotChanged(snapshot);
197 }
Jorim Jaggifb9d78a2017-01-05 18:57:12 +0100198 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800199 }
200 }
201 }
202
Jorim Jaggi7361bab2017-01-16 17:17:58 +0100203 /**
204 * Retrieves a snapshot. If {@param restoreFromDisk} equals {@code true}, DO HOLD THE WINDOW
205 * MANAGER LOCK WHEN CALLING THIS METHOD!
206 */
Jorim Jaggi35e3f532017-03-17 17:06:50 +0100207 @Nullable TaskSnapshot getSnapshot(int taskId, int userId, boolean restoreFromDisk,
208 boolean reducedResolution) {
Matthew Ngcb7ac672017-07-21 17:27:42 -0700209 return mCache.getSnapshot(taskId, userId, restoreFromDisk, reducedResolution
210 || DISABLE_FULL_SIZED_BITMAPS);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800211 }
212
213 /**
214 * Creates a starting surface for {@param token} with {@param snapshot}. DO NOT HOLD THE WINDOW
215 * MANAGER LOCK WHEN CALLING THIS METHOD!
216 */
217 StartingSurface createStartingSurface(AppWindowToken token,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200218 TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800219 return TaskSnapshotSurface.create(mService, token, snapshot);
220 }
221
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100222 private TaskSnapshot snapshotTask(Task task) {
Jorim Jaggi10abe2f2017-01-03 16:44:46 +0100223 final AppWindowToken top = task.getTopChild();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800224 if (top == null) {
225 return null;
226 }
Jorim Jaggidd5986e2017-04-11 15:50:19 -0700227 final WindowState mainWindow = top.findMainWindow();
228 if (mainWindow == null) {
229 return null;
230 }
chaviwfbe47df2017-11-10 16:14:49 -0800231 if (!mService.mPolicy.isScreenOn()) {
232 if (DEBUG_SCREENSHOT) {
233 Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
234 }
235 return null;
236 }
237 if (task.getSurfaceControl() == null) {
238 return null;
239 }
240
chaviw7f1fa992018-01-10 13:52:12 -0800241 if (top.hasCommittedReparentToAnimationLeash()) {
242 if (DEBUG_SCREENSHOT) {
243 Slog.w(TAG_WM, "Failed to take screenshot. App is animating " + top);
244 }
245 return null;
246 }
247
248 final boolean hasVisibleChild = top.forAllWindows(
249 // Ensure at least one window for the top app is visible before attempting to take
250 // a screenshot. Visible here means that the WSA surface is shown and has an alpha
251 // greater than 0.
Jorim Jaggi77d0f36c2018-03-16 17:49:49 +0100252 ws -> (ws.mAppToken == null || ws.mAppToken.isSurfaceShowing())
253 && ws.mWinAnimator != null && ws.mWinAnimator.getShown()
chaviw7f1fa992018-01-10 13:52:12 -0800254 && ws.mWinAnimator.mLastAlpha > 0f, true);
255
256 if (!hasVisibleChild) {
257 if (DEBUG_SCREENSHOT) {
258 Slog.w(TAG_WM, "Failed to take screenshot. No visible windows for " + task);
259 }
260 return null;
261 }
262
Matthew Ngcb7ac672017-07-21 17:27:42 -0700263 final boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
264 final float scaleFraction = isLowRamDevice ? REDUCED_SCALE : 1f;
chaviw23ee71c2017-12-18 11:29:41 -0800265 task.getBounds(mTmpRect);
266 mTmpRect.offsetTo(0, 0);
chaviwfbe47df2017-11-10 16:14:49 -0800267
Chavi Weingartend7ec64c2017-11-30 01:52:01 +0000268 final GraphicBuffer buffer = SurfaceControl.captureLayers(
chaviw23ee71c2017-12-18 11:29:41 -0800269 task.getSurfaceControl().getHandle(), mTmpRect, scaleFraction);
Winson Chung02378b42018-06-04 16:40:09 -0700270 final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
Juho Had864b442017-06-12 20:15:31 +0900271 if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
chaviwfbe47df2017-11-10 16:14:49 -0800272 if (DEBUG_SCREENSHOT) {
chaviw7f1fa992018-01-10 13:52:12 -0800273 Slog.w(TAG_WM, "Failed to take screenshot for " + task);
chaviwfbe47df2017-11-10 16:14:49 -0800274 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800275 return null;
276 }
Jorim Jaggie2c77f92016-12-29 14:57:22 +0100277 return new TaskSnapshot(buffer, top.getConfiguration().orientation,
Winson Chunga4fa8d52018-04-20 15:54:51 -0700278 getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */,
Winson Chung173020c2018-05-04 15:36:47 -0700279 true /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task),
Winson Chung02378b42018-06-04 16:40:09 -0700280 !top.fillsParent() || isWindowTranslucent);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200281 }
282
Keyvan Amirie681cec2017-06-05 22:48:26 -0700283 private boolean shouldDisableSnapshots() {
Jorim Jaggie7d2b852017-08-28 17:55:15 +0200284 return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
Keyvan Amirie681cec2017-06-05 22:48:26 -0700285 }
286
Jorim Jaggi817ebdd2018-03-26 15:46:01 +0200287 private Rect getInsets(WindowState state) {
Adrian Roos20e07892018-02-23 19:12:01 +0100288 // XXX(b/72757033): These are insets relative to the window frame, but we're really
289 // interested in the insets relative to the task bounds.
Jorim Jaggi817ebdd2018-03-26 15:46:01 +0200290 final Rect insets = minRect(state.mContentInsets, state.mStableInsets);
291 InsetUtils.addInsets(insets, state.mAppToken.getLetterboxInsets());
Adrian Roos20e07892018-02-23 19:12:01 +0100292 return insets;
293 }
Adrian Roos98a146d2017-11-29 16:39:44 +0100294
Adrian Roos20e07892018-02-23 19:12:01 +0100295 private Rect minRect(Rect rect1, Rect rect2) {
296 return new Rect(Math.min(rect1.left, rect2.left),
297 Math.min(rect1.top, rect2.top),
298 Math.min(rect1.right, rect2.right),
299 Math.min(rect1.bottom, rect2.bottom));
300 }
Adrian Roos98a146d2017-11-29 16:39:44 +0100301
Jorim Jaggi02886a82016-12-06 09:10:06 -0800302 /**
303 * Retrieves all closing tasks based on the list of closing apps during an app transition.
304 */
305 @VisibleForTesting
306 void getClosingTasks(ArraySet<AppWindowToken> closingApps, ArraySet<Task> outClosingTasks) {
307 outClosingTasks.clear();
308 for (int i = closingApps.size() - 1; i >= 0; i--) {
309 final AppWindowToken atoken = closingApps.valueAt(i);
Bryce Lee6d410262017-02-28 15:30:17 -0800310 final Task task = atoken.getTask();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800311
312 // If the task of the app is not visible anymore, it means no other app in that task
313 // is opening. Thus, the task is closing.
Winson Chung23aa7b12018-02-01 11:41:43 -0800314 if (task != null && !task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) {
Bryce Lee6d410262017-02-28 15:30:17 -0800315 outClosingTasks.add(task);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800316 }
317 }
318 }
319
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100320 @VisibleForTesting
Jorim Jaggi8f4fe6e2017-03-14 18:21:40 +0100321 int getSnapshotMode(Task task) {
Jorim Jaggi0fe7ce962017-02-22 16:45:48 +0100322 final AppWindowToken topChild = task.getTopChild();
Winson Chungbff18372018-04-27 16:12:54 -0700323 if (!task.isActivityTypeStandardOrUndefined() && !task.isActivityTypeAssistant()) {
Jorim Jaggi8f4fe6e2017-03-14 18:21:40 +0100324 return SNAPSHOT_MODE_NONE;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200325 } else if (topChild != null && topChild.shouldUseAppThemeSnapshot()) {
Jorim Jaggi8f4fe6e2017-03-14 18:21:40 +0100326 return SNAPSHOT_MODE_APP_THEME;
327 } else {
328 return SNAPSHOT_MODE_REAL;
329 }
330 }
331
332 /**
333 * If we are not allowed to take a real screenshot, this attempts to represent the app as best
334 * as possible by using the theme's window background.
335 */
336 private TaskSnapshot drawAppThemeSnapshot(Task task) {
337 final AppWindowToken topChild = task.getTopChild();
338 if (topChild == null) {
339 return null;
340 }
341 final WindowState mainWindow = topChild.findMainWindow();
342 if (mainWindow == null) {
343 return null;
344 }
Winson Chung51f42d22018-02-01 14:59:38 -0800345 final int color = ColorUtils.setAlphaComponent(
346 task.getTaskDescription().getBackgroundColor(), 255);
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200347 final int statusBarColor = task.getTaskDescription().getStatusBarColor();
348 final int navigationBarColor = task.getTaskDescription().getNavigationBarColor();
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200349 final LayoutParams attrs = mainWindow.getAttrs();
350 final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
351 attrs.privateFlags, attrs.systemUiVisibility, statusBarColor, navigationBarColor);
Winson Chung91092762017-05-24 14:08:48 -0700352 final int width = mainWindow.getFrameLw().width();
353 final int height = mainWindow.getFrameLw().height();
354
355 final RenderNode node = RenderNode.create("TaskSnapshotController", null);
356 node.setLeftTopRightBottom(0, 0, width, height);
357 node.setClipToBounds(false);
358 final DisplayListCanvas c = node.start(width, height);
359 c.drawColor(color);
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200360 decorPainter.setInsets(mainWindow.mContentInsets, mainWindow.mStableInsets);
361 decorPainter.drawDecors(c, null /* statusBarExcludeFrame */);
Winson Chung91092762017-05-24 14:08:48 -0700362 node.end(c);
363 final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
Winson Chung6267f992017-10-06 14:01:10 -0700364 if (hwBitmap == null) {
365 return null;
366 }
Winson Chung02378b42018-06-04 16:40:09 -0700367 // Note, the app theme snapshot is never translucent because we enforce a non-translucent
368 // color above
Jorim Jaggi6aead1c2017-05-23 15:07:44 +0200369 return new TaskSnapshot(hwBitmap.createGraphicBufferHandle(),
370 topChild.getConfiguration().orientation, mainWindow.mStableInsets,
Winson Chungf3e412e2018-03-08 11:07:40 -0800371 ActivityManager.isLowRamDeviceStatic() /* reduced */, 1.0f /* scale */,
Winson Chung173020c2018-05-04 15:36:47 -0700372 false /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task),
Winson Chung02378b42018-06-04 16:40:09 -0700373 false);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800374 }
Jorim Jaggi10abe2f2017-01-03 16:44:46 +0100375
376 /**
377 * Called when an {@link AppWindowToken} has been removed.
378 */
379 void onAppRemoved(AppWindowToken wtoken) {
Jorim Jaggi7361bab2017-01-16 17:17:58 +0100380 mCache.onAppRemoved(wtoken);
Jorim Jaggi10abe2f2017-01-03 16:44:46 +0100381 }
382
383 /**
384 * Called when the process of an {@link AppWindowToken} has died.
385 */
386 void onAppDied(AppWindowToken wtoken) {
Jorim Jaggi7361bab2017-01-16 17:17:58 +0100387 mCache.onAppDied(wtoken);
Jorim Jaggi10abe2f2017-01-03 16:44:46 +0100388 }
389
Jorim Jaggif9084ec2017-01-16 13:16:59 +0100390 void notifyTaskRemovedFromRecents(int taskId, int userId) {
Jorim Jaggi7361bab2017-01-16 17:17:58 +0100391 mCache.onTaskRemoved(taskId);
Jorim Jaggif9084ec2017-01-16 13:16:59 +0100392 mPersister.onTaskRemovedFromRecents(taskId, userId);
393 }
394
395 /**
396 * See {@link TaskSnapshotPersister#removeObsoleteFiles}
397 */
398 void removeObsoleteTaskFiles(ArraySet<Integer> persistentTaskIds, int[] runningUserIds) {
399 mPersister.removeObsoleteFiles(persistentTaskIds, runningUserIds);
400 }
401
Jorim Jaggia41b7292017-05-11 23:50:34 +0200402 /**
403 * Temporarily pauses/unpauses persisting of task snapshots.
404 *
405 * @param paused Whether task snapshot persisting should be paused.
406 */
407 void setPersisterPaused(boolean paused) {
408 mPersister.setPaused(paused);
409 }
410
Jorim Jaggi51304d72017-05-17 17:25:32 +0200411 /**
412 * Called when screen is being turned off.
413 */
414 void screenTurningOff(ScreenOffListener listener) {
Keyvan Amirie681cec2017-06-05 22:48:26 -0700415 if (shouldDisableSnapshots()) {
Jorim Jaggi51304d72017-05-17 17:25:32 +0200416 listener.onScreenOff();
417 return;
418 }
419
420 // We can't take a snapshot when screen is off, so take a snapshot now!
421 mHandler.post(() -> {
422 try {
423 synchronized (mService.mWindowMap) {
424 mTmpTasks.clear();
425 mService.mRoot.forAllTasks(task -> {
426 if (task.isVisible()) {
427 mTmpTasks.add(task);
428 }
429 });
430 snapshotTasks(mTmpTasks);
431 }
432 } finally {
433 listener.onScreenOff();
434 }
435 });
436 }
437
Winson Chung173020c2018-05-04 15:36:47 -0700438 /**
439 * @return The SystemUI visibility flags for the top fullscreen window in the given
440 * {@param task}.
441 */
442 private int getSystemUiVisibility(Task task) {
443 final AppWindowToken topFullscreenToken = task.getTopFullscreenAppToken();
444 final WindowState topFullscreenWindow = topFullscreenToken != null
445 ? topFullscreenToken.getTopFullscreenWindow()
446 : null;
447 if (topFullscreenWindow != null) {
448 return topFullscreenWindow.getSystemUiVisibility();
449 }
450 return 0;
451 }
452
Jorim Jaggi10abe2f2017-01-03 16:44:46 +0100453 void dump(PrintWriter pw, String prefix) {
454 mCache.dump(pw, prefix);
455 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800456}