blob: 469dab4e0a3ee4cc0365b664c9160e18929241ce [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;
Winson Chungbe9be7f2017-06-28 10:55:22 -070023import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020024import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
25import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
26import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
Jorim Jaggi02886a82016-12-06 09:10:06 -080027import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
28import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020029import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
30import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
31import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
32import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
33import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
34import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
35import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
Jorim Jaggi02886a82016-12-06 09:10:06 -080036import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TASK_SNAPSHOT;
37import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020038import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
39import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
40import static com.android.internal.policy.DecorView.getColorViewLeftInset;
41import static com.android.internal.policy.DecorView.getColorViewTopInset;
42import static com.android.internal.policy.DecorView.getNavigationBarRect;
Jorim Jaggie4b0f282017-05-17 15:10:29 +020043import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
Jorim Jaggi02886a82016-12-06 09:10:06 -080044import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
45import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
46
Jorim Jaggid635a4a2017-05-03 15:21:26 +020047import android.annotation.Nullable;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010048import android.app.ActivityManager.TaskDescription;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020049import android.app.ActivityManager.TaskSnapshot;
Jorim Jaggid635a4a2017-05-03 15:21:26 +020050import android.app.ActivityThread;
51import android.content.Context;
Jorim Jaggi02886a82016-12-06 09:10:06 -080052import android.graphics.Canvas;
53import android.graphics.GraphicBuffer;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010054import android.graphics.Paint;
Jorim Jaggi02886a82016-12-06 09:10:06 -080055import android.graphics.Rect;
56import android.os.Handler;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010057import android.os.Looper;
Jorim Jaggi02886a82016-12-06 09:10:06 -080058import android.os.Message;
59import android.os.RemoteException;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020060import android.os.SystemClock;
Andrii Kulian44607962017-03-16 11:06:24 -070061import android.util.MergedConfiguration;
Jorim Jaggi02886a82016-12-06 09:10:06 -080062import android.util.Slog;
Jorim Jaggi02886a82016-12-06 09:10:06 -080063import android.view.IWindowSession;
64import android.view.Surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020065import android.view.SurfaceControl;
66import android.view.SurfaceSession;
Jorim Jaggi02886a82016-12-06 09:10:06 -080067import android.view.View;
68import android.view.ViewGroup.LayoutParams;
69import android.view.WindowManager;
70import android.view.WindowManagerGlobal;
71import android.view.WindowManagerPolicy.StartingSurface;
72
Jorim Jaggi30d64f32017-04-07 16:33:17 +020073import com.android.internal.R;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010074import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020075import com.android.internal.policy.DecorView;
Jorim Jaggi02886a82016-12-06 09:10:06 -080076import com.android.internal.view.BaseIWindow;
77
78/**
79 * This class represents a starting window that shows a snapshot.
80 * <p>
81 * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
82 */
83class TaskSnapshotSurface implements StartingSurface {
84
Jorim Jaggi30d64f32017-04-07 16:33:17 +020085 private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
86
87 /**
88 * When creating the starting window, we use the exact same layout flags such that we end up
89 * with a window with the exact same dimensions etc. However, these flags are not used in layout
90 * and might cause other side effects so we exclude them.
91 */
92 private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
93 | FLAG_NOT_TOUCHABLE
94 | FLAG_NOT_TOUCH_MODAL
95 | FLAG_ALT_FOCUSABLE_IM
96 | FLAG_NOT_FOCUSABLE
97 | FLAG_HARDWARE_ACCELERATED
98 | FLAG_IGNORE_CHEEK_PRESSES
99 | FLAG_LOCAL_FOCUS_MODE
100 | FLAG_SLIPPERY
101 | FLAG_WATCH_OUTSIDE_TOUCH
102 | FLAG_SPLIT_TOUCH
103 | FLAG_SCALED
104 | FLAG_SECURE;
105
Jorim Jaggid2616322017-06-07 12:38:19 -0700106 private static final int PRIVATE_FLAG_INHERITS = PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
107
Jorim Jaggi02886a82016-12-06 09:10:06 -0800108 private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
109 private static final int MSG_REPORT_DRAW = 0;
110 private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
111 private final Window mWindow;
112 private final Surface mSurface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200113 private SurfaceControl mChildSurfaceControl;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800114 private final IWindowSession mSession;
115 private final WindowManagerService mService;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200116 private final Rect mTaskBounds;
117 private final Rect mStableInsets = new Rect();
118 private final Rect mContentInsets = new Rect();
119 private final Rect mFrame = new Rect();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200120 private TaskSnapshot mSnapshot;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200121 private final CharSequence mTitle;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800122 private boolean mHasDrawn;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200123 private long mShownTime;
124 private final Handler mHandler;
125 private boolean mSizeMismatch;
126 private final Paint mBackgroundPaint = new Paint();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200127 private final int mStatusBarColor;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200128 @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700129 private final int mOrientationOnCreation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800130
131 static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200132 TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800133
134 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
135 final Window window = new Window();
136 final IWindowSession session = WindowManagerGlobal.getWindowSession();
137 window.setSession(session);
138 final Surface surface = new Surface();
139 final Rect tmpRect = new Rect();
140 final Rect tmpFrame = new Rect();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200141 final Rect taskBounds;
142 final Rect tmpContentInsets = new Rect();
143 final Rect tmpStableInsets = new Rect();
Andrii Kulian44607962017-03-16 11:06:24 -0700144 final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200145 int backgroundColor = WHITE;
146 int statusBarColor = 0;
147 int navigationBarColor = 0;
148 final int sysUiVis;
149 final int windowFlags;
150 final int windowPrivateFlags;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700151 final int currentOrientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800152 synchronized (service.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200153 final WindowState mainWindow = token.findMainWindow();
154 if (mainWindow == null) {
155 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
156 + token);
157 return null;
158 }
159 sysUiVis = mainWindow.getSystemUiVisibility();
160 windowFlags = mainWindow.getAttrs().flags;
161 windowPrivateFlags = mainWindow.getAttrs().privateFlags;
162
Winson Chungbe9be7f2017-06-28 10:55:22 -0700163 layoutParams.dimAmount = mainWindow.getAttrs().dimAmount;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800164 layoutParams.type = TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200165 layoutParams.format = snapshot.getSnapshot().getFormat();
166 layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
Jorim Jaggi02886a82016-12-06 09:10:06 -0800167 | FLAG_NOT_FOCUSABLE
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200168 | FLAG_NOT_TOUCHABLE;
Jorim Jaggid2616322017-06-07 12:38:19 -0700169 layoutParams.privateFlags = PRIVATE_FLAG_TASK_SNAPSHOT
170 | (windowPrivateFlags & PRIVATE_FLAG_INHERITS);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800171 layoutParams.token = token.token;
172 layoutParams.width = LayoutParams.MATCH_PARENT;
173 layoutParams.height = LayoutParams.MATCH_PARENT;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200174 layoutParams.systemUiVisibility = sysUiVis;
Bryce Lee6d410262017-02-28 15:30:17 -0800175 final Task task = token.getTask();
176 if (task != null) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200177 layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
Bryce Lee6d410262017-02-28 15:30:17 -0800178
179 final TaskDescription taskDescription = task.getTaskDescription();
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100180 if (taskDescription != null) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200181 backgroundColor = taskDescription.getBackgroundColor();
182 statusBarColor = taskDescription.getStatusBarColor();
183 navigationBarColor = taskDescription.getNavigationBarColor();
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100184 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200185 taskBounds = new Rect();
186 task.getBounds(taskBounds);
187 } else {
188 taskBounds = null;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100189 }
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700190 currentOrientation = mainWindow.getConfiguration().orientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800191 }
192 try {
193 final int res = session.addToDisplay(window, window.mSeq, layoutParams,
194 View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
195 tmpRect, null);
196 if (res < 0) {
197 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
198 return null;
199 }
200 } catch (RemoteException e) {
201 // Local call.
202 }
203 final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200204 surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700205 navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
206 currentOrientation);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800207 window.setOuter(snapshotSurface);
208 try {
209 session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200210 tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
211 tmpMergedConfiguration, surface);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800212 } catch (RemoteException e) {
213 // Local call.
214 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200215 snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
216 snapshotSurface.drawSnapshot();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800217 return snapshotSurface;
218 }
219
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100220 @VisibleForTesting
221 TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200222 TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
223 int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700224 Rect taskBounds, int currentOrientation) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800225 mService = service;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200226 mHandler = new Handler(mService.mH.getLooper());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800227 mSession = WindowManagerGlobal.getWindowSession();
228 mWindow = window;
229 mSurface = surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200230 mSnapshot = snapshot;
231 mTitle = title;
232 mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
233 mTaskBounds = taskBounds;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200234 mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
235 windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
236 mStatusBarColor = statusBarColor;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700237 mOrientationOnCreation = currentOrientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800238 }
239
240 @Override
241 public void remove() {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200242 synchronized (mService.mWindowMap) {
243 final long now = SystemClock.uptimeMillis();
244 if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
245 mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200246 if (DEBUG_STARTING_WINDOW) {
247 Slog.v(TAG, "Defer removing snapshot surface in " + (now - mShownTime) + "ms");
248 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200249 return;
250 }
251 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800252 try {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200253 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing snapshot surface");
Jorim Jaggi02886a82016-12-06 09:10:06 -0800254 mSession.remove(mWindow);
255 } catch (RemoteException e) {
256 // Local call.
257 }
258 }
259
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200260 @VisibleForTesting
261 void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
262 mFrame.set(frame);
263 mContentInsets.set(contentInsets);
264 mStableInsets.set(stableInsets);
265 mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
266 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200267 mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200268 }
269
270 private void drawSnapshot() {
271 final GraphicBuffer buffer = mSnapshot.getSnapshot();
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200272 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
273 + mSizeMismatch);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200274 if (mSizeMismatch) {
275 // The dimensions of the buffer and the window don't match, so attaching the buffer
276 // will fail. Better create a child window with the exact dimensions and fill the parent
277 // window with the background color!
278 drawSizeMismatchSnapshot(buffer);
279 } else {
280 drawSizeMatchSnapshot(buffer);
281 }
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100282 synchronized (mService.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200283 mShownTime = SystemClock.uptimeMillis();
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100284 mHasDrawn = true;
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100285 }
Jorim Jaggidc9385a2017-05-13 02:00:31 +0200286 reportDrawn();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200287
288 // In case window manager leaks us, make sure we don't retain the snapshot.
289 mSnapshot = null;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200290 }
291
292 private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
293 mSurface.attachAndQueueBuffer(buffer);
294 mSurface.release();
295 }
296
297 private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
298 final SurfaceSession session = new SurfaceSession(mSurface);
299
300 // Keep a reference to it such that it doesn't get destroyed when finalized.
301 mChildSurfaceControl = new SurfaceControl(session,
302 mTitle + " - task-snapshot-surface",
303 buffer.getWidth(), buffer.getHeight(), buffer.getFormat(), HIDDEN);
304 Surface surface = new Surface();
305 surface.copyFrom(mChildSurfaceControl);
306
307 // Clip off ugly navigation bar.
308 final Rect crop = calculateSnapshotCrop();
309 final Rect frame = calculateSnapshotFrame(crop);
310 SurfaceControl.openTransaction();
311 try {
312 // We can just show the surface here as it will still be hidden as the parent is
313 // still hidden.
314 mChildSurfaceControl.show();
315 mChildSurfaceControl.setWindowCrop(crop);
316 mChildSurfaceControl.setPosition(frame.left, frame.top);
317 } finally {
318 SurfaceControl.closeTransaction();
319 }
320 surface.attachAndQueueBuffer(buffer);
321 surface.release();
322
323 final Canvas c = mSurface.lockCanvas(null);
324 drawBackgroundAndBars(c, frame);
325 mSurface.unlockCanvasAndPost(c);
Jorim Jaggi2f24b652017-01-18 02:17:37 +0100326 mSurface.release();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800327 }
328
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100329 @VisibleForTesting
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200330 Rect calculateSnapshotCrop() {
331 final Rect rect = new Rect();
332 rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
333 final Rect insets = mSnapshot.getContentInsets();
334
335 // Let's remove all system decorations except the status bar, but only if the task is at the
336 // very top of the screen.
337 rect.inset(insets.left, mTaskBounds.top != 0 ? insets.top : 0, insets.right, insets.bottom);
338 return rect;
339 }
340
341 @VisibleForTesting
342 Rect calculateSnapshotFrame(Rect crop) {
343 final Rect frame = new Rect(crop);
344
345 // By default, offset it to to top/left corner
346 frame.offsetTo(-crop.left, -crop.top);
347
348 // However, we also need to make space for the navigation bar on the left side.
349 final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
350 mContentInsets.left);
351 frame.offset(colorViewLeftInset, 0);
352 return frame;
353 }
354
355 @VisibleForTesting
356 void drawBackgroundAndBars(Canvas c, Rect frame) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200357 final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200358 final boolean fillHorizontally = c.getWidth() > frame.right;
359 final boolean fillVertically = c.getHeight() > frame.bottom;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100360 if (fillHorizontally) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200361 c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
362 c.getWidth(), fillVertically
363 ? frame.bottom
364 : c.getHeight(),
365 mBackgroundPaint);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100366 }
367 if (fillVertically) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200368 c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
369 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200370 mSystemBarBackgroundPainter.drawDecors(c, frame);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100371 }
372
Jorim Jaggi02886a82016-12-06 09:10:06 -0800373 private void reportDrawn() {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800374 try {
375 mSession.finishDrawing(mWindow);
376 } catch (RemoteException e) {
377 // Local call.
378 }
379 }
380
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100381 private static Handler sHandler = new Handler(Looper.getMainLooper()) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800382
383 @Override
384 public void handleMessage(Message msg) {
385 switch (msg.what) {
386 case MSG_REPORT_DRAW:
387 final boolean hasDrawn;
388 final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
389 synchronized (surface.mService.mWindowMap) {
390 hasDrawn = surface.mHasDrawn;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800391 }
392 if (hasDrawn) {
393 surface.reportDrawn();
394 }
395 break;
396 }
397 }
398 };
399
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200400 @VisibleForTesting
401 static class Window extends BaseIWindow {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800402
403 private TaskSnapshotSurface mOuter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700404
Jorim Jaggi02886a82016-12-06 09:10:06 -0800405 public void setOuter(TaskSnapshotSurface outer) {
406 mOuter = outer;
407 }
408
409 @Override
410 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Andrii Kulian44607962017-03-16 11:06:24 -0700411 Rect stableInsets, Rect outsets, boolean reportDraw,
412 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
413 boolean alwaysConsumeNavBar, int displayId) {
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700414 if (mergedConfiguration != null && mOuter != null
415 && mOuter.mOrientationOnCreation
416 != mergedConfiguration.getMergedConfiguration().orientation) {
417
418 // The orientation of the screen is changing. We better remove the snapshot ASAP as
419 // we are going to wait on the new window in any case to unfreeze the screen, and
420 // the starting window is not needed anymore.
421 sHandler.post(mOuter::remove);
422 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800423 if (reportDraw) {
424 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
425 }
426 }
427 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200428
429 /**
430 * Helper class to draw the background of the system bars in regions the task snapshot isn't
431 * filling the window.
432 */
433 static class SystemBarBackgroundPainter {
434
435 private final Rect mContentInsets = new Rect();
436 private final Rect mStableInsets = new Rect();
437 private final Paint mStatusBarPaint = new Paint();
438 private final Paint mNavigationBarPaint = new Paint();
439 private final int mStatusBarColor;
440 private final int mNavigationBarColor;
441 private final int mWindowFlags;
442 private final int mWindowPrivateFlags;
443 private final int mSysUiVis;
444
445 SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
446 int statusBarColor, int navigationBarColor) {
447 mWindowFlags = windowFlags;
448 mWindowPrivateFlags = windowPrivateFlags;
449 mSysUiVis = sysUiVis;
450 final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
451 mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
452 context.getColor(R.color.system_bar_background_semi_transparent),
453 statusBarColor);
454 mNavigationBarColor = navigationBarColor;
455 mStatusBarPaint.setColor(mStatusBarColor);
456 mNavigationBarPaint.setColor(navigationBarColor);
457 }
458
459 void setInsets(Rect contentInsets, Rect stableInsets) {
460 mContentInsets.set(contentInsets);
461 mStableInsets.set(stableInsets);
462 }
463
464 int getStatusBarColorViewHeight() {
465 final boolean forceStatusBarBackground =
466 (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
467 if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
468 mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
469 return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
470 } else {
471 return 0;
472 }
473 }
474
475 private boolean isNavigationBarColorViewVisible() {
476 return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
477 mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
478 }
479
480 void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
481 drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
482 drawNavigationBarBackground(c);
483 }
484
485 @VisibleForTesting
486 void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
487 int statusBarHeight) {
488 if (statusBarHeight > 0
489 && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
490 final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
491 mContentInsets.right);
492 final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
493 c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
494 }
495 }
496
497 @VisibleForTesting
498 void drawNavigationBarBackground(Canvas c) {
499 final Rect navigationBarRect = new Rect();
500 getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
501 navigationBarRect);
502 final boolean visible = isNavigationBarColorViewVisible();
503 if (visible && !navigationBarRect.isEmpty()) {
504 c.drawRect(navigationBarRect, mNavigationBarPaint);
505 }
506 }
507 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800508}