blob: 5e7b9100af4eeacf0df4c9d80487e6a922a64dc9 [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
Jorim Jaggi30d64f32017-04-07 16:33:17 +020019import static android.graphics.Color.WHITE;
20import static android.graphics.Color.alpha;
21import static android.view.SurfaceControl.HIDDEN;
22import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
23import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
24import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
25import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
Jorim Jaggi02886a82016-12-06 09:10:06 -080026import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
27import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020028import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
29import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
30import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
31import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
32import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
33import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
34import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
Jorim Jaggi02886a82016-12-06 09:10:06 -080035import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
36import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020037import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
38import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
39import static com.android.internal.policy.DecorView.getColorViewLeftInset;
40import static com.android.internal.policy.DecorView.getColorViewTopInset;
41import static com.android.internal.policy.DecorView.getNavigationBarRect;
Jorim Jaggi02886a82016-12-06 09:10:06 -080042import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
43import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
44
Jorim Jaggid635a4a2017-05-03 15:21:26 +020045import android.annotation.Nullable;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010046import android.app.ActivityManager.TaskDescription;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020047import android.app.ActivityManager.TaskSnapshot;
Jorim Jaggid635a4a2017-05-03 15:21:26 +020048import android.app.ActivityThread;
49import android.content.Context;
Jorim Jaggi02886a82016-12-06 09:10:06 -080050import android.graphics.Canvas;
51import android.graphics.GraphicBuffer;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010052import android.graphics.Paint;
Jorim Jaggi02886a82016-12-06 09:10:06 -080053import android.graphics.Rect;
54import android.os.Handler;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010055import android.os.Looper;
Jorim Jaggi02886a82016-12-06 09:10:06 -080056import android.os.Message;
57import android.os.RemoteException;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020058import android.os.SystemClock;
Andrii Kulian44607962017-03-16 11:06:24 -070059import android.util.MergedConfiguration;
Jorim Jaggi02886a82016-12-06 09:10:06 -080060import android.util.Slog;
Jorim Jaggi02886a82016-12-06 09:10:06 -080061import android.view.IWindowSession;
62import android.view.Surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020063import android.view.SurfaceControl;
64import android.view.SurfaceSession;
Jorim Jaggi02886a82016-12-06 09:10:06 -080065import android.view.View;
66import android.view.ViewGroup.LayoutParams;
67import android.view.WindowManager;
68import android.view.WindowManagerGlobal;
69import android.view.WindowManagerPolicy.StartingSurface;
70
Jorim Jaggi30d64f32017-04-07 16:33:17 +020071import com.android.internal.R;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010072import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020073import com.android.internal.policy.DecorView;
Jorim Jaggi02886a82016-12-06 09:10:06 -080074import com.android.internal.view.BaseIWindow;
75
76/**
77 * This class represents a starting window that shows a snapshot.
78 * <p>
79 * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
80 */
81class TaskSnapshotSurface implements StartingSurface {
82
Jorim Jaggi30d64f32017-04-07 16:33:17 +020083 private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
84
85 /**
86 * When creating the starting window, we use the exact same layout flags such that we end up
87 * with a window with the exact same dimensions etc. However, these flags are not used in layout
88 * and might cause other side effects so we exclude them.
89 */
90 private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
91 | FLAG_NOT_TOUCHABLE
92 | FLAG_NOT_TOUCH_MODAL
93 | FLAG_ALT_FOCUSABLE_IM
94 | FLAG_NOT_FOCUSABLE
95 | FLAG_HARDWARE_ACCELERATED
96 | FLAG_IGNORE_CHEEK_PRESSES
97 | FLAG_LOCAL_FOCUS_MODE
98 | FLAG_SLIPPERY
99 | FLAG_WATCH_OUTSIDE_TOUCH
100 | FLAG_SPLIT_TOUCH
101 | FLAG_SCALED
102 | FLAG_SECURE;
103
Jorim Jaggi02886a82016-12-06 09:10:06 -0800104 private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
105 private static final int MSG_REPORT_DRAW = 0;
106 private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
107 private final Window mWindow;
108 private final Surface mSurface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200109 private SurfaceControl mChildSurfaceControl;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800110 private final IWindowSession mSession;
111 private final WindowManagerService mService;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200112 private final Rect mTaskBounds;
113 private final Rect mStableInsets = new Rect();
114 private final Rect mContentInsets = new Rect();
115 private final Rect mFrame = new Rect();
116 private final TaskSnapshot mSnapshot;
117 private final CharSequence mTitle;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800118 private boolean mHasDrawn;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200119 private long mShownTime;
120 private final Handler mHandler;
121 private boolean mSizeMismatch;
122 private final Paint mBackgroundPaint = new Paint();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200123 private final int mStatusBarColor;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200124 @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800125
126 static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200127 TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800128
129 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
130 final Window window = new Window();
131 final IWindowSession session = WindowManagerGlobal.getWindowSession();
132 window.setSession(session);
133 final Surface surface = new Surface();
134 final Rect tmpRect = new Rect();
135 final Rect tmpFrame = new Rect();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200136 final Rect taskBounds;
137 final Rect tmpContentInsets = new Rect();
138 final Rect tmpStableInsets = new Rect();
Andrii Kulian44607962017-03-16 11:06:24 -0700139 final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200140 int backgroundColor = WHITE;
141 int statusBarColor = 0;
142 int navigationBarColor = 0;
143 final int sysUiVis;
144 final int windowFlags;
145 final int windowPrivateFlags;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800146 synchronized (service.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200147 final WindowState mainWindow = token.findMainWindow();
148 if (mainWindow == null) {
149 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
150 + token);
151 return null;
152 }
153 sysUiVis = mainWindow.getSystemUiVisibility();
154 windowFlags = mainWindow.getAttrs().flags;
155 windowPrivateFlags = mainWindow.getAttrs().privateFlags;
156
Jorim Jaggi02886a82016-12-06 09:10:06 -0800157 layoutParams.type = TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200158 layoutParams.format = snapshot.getSnapshot().getFormat();
159 layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
Jorim Jaggi02886a82016-12-06 09:10:06 -0800160 | FLAG_NOT_FOCUSABLE
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200161 | FLAG_NOT_TOUCHABLE;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800162 layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT;
163 layoutParams.token = token.token;
164 layoutParams.width = LayoutParams.MATCH_PARENT;
165 layoutParams.height = LayoutParams.MATCH_PARENT;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200166 layoutParams.systemUiVisibility = sysUiVis;
Bryce Lee6d410262017-02-28 15:30:17 -0800167 final Task task = token.getTask();
168 if (task != null) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200169 layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
Bryce Lee6d410262017-02-28 15:30:17 -0800170
171 final TaskDescription taskDescription = task.getTaskDescription();
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100172 if (taskDescription != null) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200173 backgroundColor = taskDescription.getBackgroundColor();
174 statusBarColor = taskDescription.getStatusBarColor();
175 navigationBarColor = taskDescription.getNavigationBarColor();
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100176 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200177 taskBounds = new Rect();
178 task.getBounds(taskBounds);
179 } else {
180 taskBounds = null;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100181 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800182 }
183 try {
184 final int res = session.addToDisplay(window, window.mSeq, layoutParams,
185 View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
186 tmpRect, null);
187 if (res < 0) {
188 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
189 return null;
190 }
191 } catch (RemoteException e) {
192 // Local call.
193 }
194 final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200195 surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
196 navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800197 window.setOuter(snapshotSurface);
198 try {
199 session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200200 tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
201 tmpMergedConfiguration, surface);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800202 } catch (RemoteException e) {
203 // Local call.
204 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200205 snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
206 snapshotSurface.drawSnapshot();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800207 return snapshotSurface;
208 }
209
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100210 @VisibleForTesting
211 TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200212 TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
213 int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
214 Rect taskBounds) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800215 mService = service;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200216 mHandler = new Handler(mService.mH.getLooper());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800217 mSession = WindowManagerGlobal.getWindowSession();
218 mWindow = window;
219 mSurface = surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200220 mSnapshot = snapshot;
221 mTitle = title;
222 mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
223 mTaskBounds = taskBounds;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200224 mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
225 windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
226 mStatusBarColor = statusBarColor;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800227 }
228
229 @Override
230 public void remove() {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200231 synchronized (mService.mWindowMap) {
232 final long now = SystemClock.uptimeMillis();
233 if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
234 mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
235 return;
236 }
237 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800238 try {
239 mSession.remove(mWindow);
240 } catch (RemoteException e) {
241 // Local call.
242 }
243 }
244
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200245 @VisibleForTesting
246 void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
247 mFrame.set(frame);
248 mContentInsets.set(contentInsets);
249 mStableInsets.set(stableInsets);
250 mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
251 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200252 mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200253 }
254
255 private void drawSnapshot() {
256 final GraphicBuffer buffer = mSnapshot.getSnapshot();
257 if (mSizeMismatch) {
258 // The dimensions of the buffer and the window don't match, so attaching the buffer
259 // will fail. Better create a child window with the exact dimensions and fill the parent
260 // window with the background color!
261 drawSizeMismatchSnapshot(buffer);
262 } else {
263 drawSizeMatchSnapshot(buffer);
264 }
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100265 synchronized (mService.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200266 mShownTime = SystemClock.uptimeMillis();
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100267 mHasDrawn = true;
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100268 }
Jorim Jaggidc9385a2017-05-13 02:00:31 +0200269 reportDrawn();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200270 }
271
272 private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
273 mSurface.attachAndQueueBuffer(buffer);
274 mSurface.release();
275 }
276
277 private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
278 final SurfaceSession session = new SurfaceSession(mSurface);
279
280 // Keep a reference to it such that it doesn't get destroyed when finalized.
281 mChildSurfaceControl = new SurfaceControl(session,
282 mTitle + " - task-snapshot-surface",
283 buffer.getWidth(), buffer.getHeight(), buffer.getFormat(), HIDDEN);
284 Surface surface = new Surface();
285 surface.copyFrom(mChildSurfaceControl);
286
287 // Clip off ugly navigation bar.
288 final Rect crop = calculateSnapshotCrop();
289 final Rect frame = calculateSnapshotFrame(crop);
290 SurfaceControl.openTransaction();
291 try {
292 // We can just show the surface here as it will still be hidden as the parent is
293 // still hidden.
294 mChildSurfaceControl.show();
295 mChildSurfaceControl.setWindowCrop(crop);
296 mChildSurfaceControl.setPosition(frame.left, frame.top);
297 } finally {
298 SurfaceControl.closeTransaction();
299 }
300 surface.attachAndQueueBuffer(buffer);
301 surface.release();
302
303 final Canvas c = mSurface.lockCanvas(null);
304 drawBackgroundAndBars(c, frame);
305 mSurface.unlockCanvasAndPost(c);
Jorim Jaggi2f24b652017-01-18 02:17:37 +0100306 mSurface.release();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800307 }
308
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100309 @VisibleForTesting
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200310 Rect calculateSnapshotCrop() {
311 final Rect rect = new Rect();
312 rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
313 final Rect insets = mSnapshot.getContentInsets();
314
315 // Let's remove all system decorations except the status bar, but only if the task is at the
316 // very top of the screen.
317 rect.inset(insets.left, mTaskBounds.top != 0 ? insets.top : 0, insets.right, insets.bottom);
318 return rect;
319 }
320
321 @VisibleForTesting
322 Rect calculateSnapshotFrame(Rect crop) {
323 final Rect frame = new Rect(crop);
324
325 // By default, offset it to to top/left corner
326 frame.offsetTo(-crop.left, -crop.top);
327
328 // However, we also need to make space for the navigation bar on the left side.
329 final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
330 mContentInsets.left);
331 frame.offset(colorViewLeftInset, 0);
332 return frame;
333 }
334
335 @VisibleForTesting
336 void drawBackgroundAndBars(Canvas c, Rect frame) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200337 final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200338 final boolean fillHorizontally = c.getWidth() > frame.right;
339 final boolean fillVertically = c.getHeight() > frame.bottom;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100340 if (fillHorizontally) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200341 c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
342 c.getWidth(), fillVertically
343 ? frame.bottom
344 : c.getHeight(),
345 mBackgroundPaint);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100346 }
347 if (fillVertically) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200348 c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
349 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200350 mSystemBarBackgroundPainter.drawDecors(c, frame);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100351 }
352
Jorim Jaggi02886a82016-12-06 09:10:06 -0800353 private void reportDrawn() {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800354 try {
355 mSession.finishDrawing(mWindow);
356 } catch (RemoteException e) {
357 // Local call.
358 }
359 }
360
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100361 private static Handler sHandler = new Handler(Looper.getMainLooper()) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800362
363 @Override
364 public void handleMessage(Message msg) {
365 switch (msg.what) {
366 case MSG_REPORT_DRAW:
367 final boolean hasDrawn;
368 final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
369 synchronized (surface.mService.mWindowMap) {
370 hasDrawn = surface.mHasDrawn;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800371 }
372 if (hasDrawn) {
373 surface.reportDrawn();
374 }
375 break;
376 }
377 }
378 };
379
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200380 @VisibleForTesting
381 static class Window extends BaseIWindow {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800382
383 private TaskSnapshotSurface mOuter;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800384 public void setOuter(TaskSnapshotSurface outer) {
385 mOuter = outer;
386 }
387
388 @Override
389 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Andrii Kulian44607962017-03-16 11:06:24 -0700390 Rect stableInsets, Rect outsets, boolean reportDraw,
391 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
392 boolean alwaysConsumeNavBar, int displayId) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800393 if (reportDraw) {
394 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
395 }
396 }
397 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200398
399 /**
400 * Helper class to draw the background of the system bars in regions the task snapshot isn't
401 * filling the window.
402 */
403 static class SystemBarBackgroundPainter {
404
405 private final Rect mContentInsets = new Rect();
406 private final Rect mStableInsets = new Rect();
407 private final Paint mStatusBarPaint = new Paint();
408 private final Paint mNavigationBarPaint = new Paint();
409 private final int mStatusBarColor;
410 private final int mNavigationBarColor;
411 private final int mWindowFlags;
412 private final int mWindowPrivateFlags;
413 private final int mSysUiVis;
414
415 SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
416 int statusBarColor, int navigationBarColor) {
417 mWindowFlags = windowFlags;
418 mWindowPrivateFlags = windowPrivateFlags;
419 mSysUiVis = sysUiVis;
420 final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
421 mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
422 context.getColor(R.color.system_bar_background_semi_transparent),
423 statusBarColor);
424 mNavigationBarColor = navigationBarColor;
425 mStatusBarPaint.setColor(mStatusBarColor);
426 mNavigationBarPaint.setColor(navigationBarColor);
427 }
428
429 void setInsets(Rect contentInsets, Rect stableInsets) {
430 mContentInsets.set(contentInsets);
431 mStableInsets.set(stableInsets);
432 }
433
434 int getStatusBarColorViewHeight() {
435 final boolean forceStatusBarBackground =
436 (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
437 if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
438 mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
439 return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
440 } else {
441 return 0;
442 }
443 }
444
445 private boolean isNavigationBarColorViewVisible() {
446 return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
447 mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
448 }
449
450 void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
451 drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
452 drawNavigationBarBackground(c);
453 }
454
455 @VisibleForTesting
456 void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
457 int statusBarHeight) {
458 if (statusBarHeight > 0
459 && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
460 final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
461 mContentInsets.right);
462 final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
463 c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
464 }
465 }
466
467 @VisibleForTesting
468 void drawNavigationBarBackground(Canvas c) {
469 final Rect navigationBarRect = new Rect();
470 getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
471 navigationBarRect);
472 final boolean visible = isNavigationBarColorViewVisible();
473 if (visible && !navigationBarRect.isEmpty()) {
474 c.drawRect(navigationBarRect, mNavigationBarPaint);
475 }
476 }
477 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800478}