blob: 57f754f8234dd622d0c0471dbf583656549e5aa0 [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;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020021import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
22import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
23import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
24import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
Jorim Jaggi02886a82016-12-06 09:10:06 -080025import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
26import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020027import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
28import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
29import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
30import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
31import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
32import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
33import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
Jorim Jaggi02886a82016-12-06 09:10:06 -080034import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020035import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
36import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
37import static com.android.internal.policy.DecorView.getColorViewLeftInset;
38import static com.android.internal.policy.DecorView.getColorViewTopInset;
39import static com.android.internal.policy.DecorView.getNavigationBarRect;
Jorim Jaggie4b0f282017-05-17 15:10:29 +020040import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
Jorim Jaggi02886a82016-12-06 09:10:06 -080041import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
42import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
43
Jorim Jaggid635a4a2017-05-03 15:21:26 +020044import android.annotation.Nullable;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010045import android.app.ActivityManager.TaskDescription;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020046import android.app.ActivityManager.TaskSnapshot;
Jorim Jaggid635a4a2017-05-03 15:21:26 +020047import android.app.ActivityThread;
48import android.content.Context;
Jorim Jaggi02886a82016-12-06 09:10:06 -080049import android.graphics.Canvas;
50import android.graphics.GraphicBuffer;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010051import android.graphics.Paint;
Jorim Jaggi02886a82016-12-06 09:10:06 -080052import android.graphics.Rect;
53import android.os.Handler;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010054import android.os.Looper;
Jorim Jaggi02886a82016-12-06 09:10:06 -080055import android.os.Message;
56import android.os.RemoteException;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020057import android.os.SystemClock;
Andrii Kulian44607962017-03-16 11:06:24 -070058import android.util.MergedConfiguration;
Jorim Jaggi02886a82016-12-06 09:10:06 -080059import android.util.Slog;
Jorim Jaggi02886a82016-12-06 09:10:06 -080060import android.view.IWindowSession;
61import android.view.Surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020062import android.view.SurfaceControl;
63import android.view.SurfaceSession;
Jorim Jaggi02886a82016-12-06 09:10:06 -080064import android.view.View;
65import android.view.ViewGroup.LayoutParams;
66import android.view.WindowManager;
67import android.view.WindowManagerGlobal;
Jorim Jaggi02886a82016-12-06 09:10:06 -080068
Jorim Jaggi30d64f32017-04-07 16:33:17 +020069import com.android.internal.R;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010070import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020071import com.android.internal.policy.DecorView;
Jorim Jaggi02886a82016-12-06 09:10:06 -080072import com.android.internal.view.BaseIWindow;
Adrian Roose99bc052017-11-20 17:55:31 +010073import com.android.server.policy.WindowManagerPolicy.StartingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -080074
75/**
76 * This class represents a starting window that shows a snapshot.
77 * <p>
78 * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
79 */
80class TaskSnapshotSurface implements StartingSurface {
81
Jorim Jaggi30d64f32017-04-07 16:33:17 +020082 private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
83
84 /**
85 * When creating the starting window, we use the exact same layout flags such that we end up
86 * with a window with the exact same dimensions etc. However, these flags are not used in layout
87 * and might cause other side effects so we exclude them.
88 */
89 private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
90 | FLAG_NOT_TOUCHABLE
91 | FLAG_NOT_TOUCH_MODAL
92 | FLAG_ALT_FOCUSABLE_IM
93 | FLAG_NOT_FOCUSABLE
94 | FLAG_HARDWARE_ACCELERATED
95 | FLAG_IGNORE_CHEEK_PRESSES
96 | FLAG_LOCAL_FOCUS_MODE
97 | FLAG_SLIPPERY
98 | FLAG_WATCH_OUTSIDE_TOUCH
99 | FLAG_SPLIT_TOUCH
100 | FLAG_SCALED
101 | FLAG_SECURE;
102
Jorim Jaggid2616322017-06-07 12:38:19 -0700103 private static final int PRIVATE_FLAG_INHERITS = PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
104
Jorim Jaggi02886a82016-12-06 09:10:06 -0800105 private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
106 private static final int MSG_REPORT_DRAW = 0;
107 private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
108 private final Window mWindow;
109 private final Surface mSurface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200110 private SurfaceControl mChildSurfaceControl;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800111 private final IWindowSession mSession;
112 private final WindowManagerService mService;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200113 private final Rect mTaskBounds;
114 private final Rect mStableInsets = new Rect();
115 private final Rect mContentInsets = new Rect();
116 private final Rect mFrame = new Rect();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200117 private TaskSnapshot mSnapshot;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200118 private final CharSequence mTitle;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800119 private boolean mHasDrawn;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200120 private long mShownTime;
121 private final Handler mHandler;
122 private boolean mSizeMismatch;
123 private final Paint mBackgroundPaint = new Paint();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200124 private final int mStatusBarColor;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200125 @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700126 private final int mOrientationOnCreation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800127
128 static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200129 TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800130
131 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
132 final Window window = new Window();
133 final IWindowSession session = WindowManagerGlobal.getWindowSession();
134 window.setSession(session);
135 final Surface surface = new Surface();
136 final Rect tmpRect = new Rect();
137 final Rect tmpFrame = new Rect();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200138 final Rect taskBounds;
139 final Rect tmpContentInsets = new Rect();
140 final Rect tmpStableInsets = new Rect();
Andrii Kulian44607962017-03-16 11:06:24 -0700141 final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200142 int backgroundColor = WHITE;
143 int statusBarColor = 0;
144 int navigationBarColor = 0;
145 final int sysUiVis;
146 final int windowFlags;
147 final int windowPrivateFlags;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700148 final int currentOrientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800149 synchronized (service.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200150 final WindowState mainWindow = token.findMainWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200151 final Task task = token.getTask();
152 if (task == null) {
153 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for token="
154 + token);
155 return null;
156 }
157 final AppWindowToken topFullscreenToken = token.getTask().getTopFullscreenAppToken();
158 if (topFullscreenToken == null) {
159 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
160 + task);
161 return null;
162 }
Jorim Jaggi87fdbcb2017-08-17 13:41:11 +0200163 final WindowState topFullscreenWindow = topFullscreenToken.getTopFullscreenWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200164 if (mainWindow == null || topFullscreenWindow == null) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200165 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
166 + token);
167 return null;
168 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200169 sysUiVis = topFullscreenWindow.getSystemUiVisibility();
170 windowFlags = topFullscreenWindow.getAttrs().flags;
171 windowPrivateFlags = topFullscreenWindow.getAttrs().privateFlags;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200172
Winson Chungbe9be7f2017-06-28 10:55:22 -0700173 layoutParams.dimAmount = mainWindow.getAttrs().dimAmount;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800174 layoutParams.type = TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200175 layoutParams.format = snapshot.getSnapshot().getFormat();
176 layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
Jorim Jaggi02886a82016-12-06 09:10:06 -0800177 | FLAG_NOT_FOCUSABLE
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200178 | FLAG_NOT_TOUCHABLE;
Wale Ogunwale01ad4342017-06-30 07:07:01 -0700179 layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800180 layoutParams.token = token.token;
181 layoutParams.width = LayoutParams.MATCH_PARENT;
182 layoutParams.height = LayoutParams.MATCH_PARENT;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200183 layoutParams.systemUiVisibility = sysUiVis;
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200184 layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
Bryce Lee6d410262017-02-28 15:30:17 -0800185
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200186 final TaskDescription taskDescription = task.getTaskDescription();
187 if (taskDescription != null) {
188 backgroundColor = taskDescription.getBackgroundColor();
189 statusBarColor = taskDescription.getStatusBarColor();
190 navigationBarColor = taskDescription.getNavigationBarColor();
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100191 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200192 taskBounds = new Rect();
193 task.getBounds(taskBounds);
194 currentOrientation = topFullscreenWindow.getConfiguration().orientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800195 }
196 try {
197 final int res = session.addToDisplay(window, window.mSeq, layoutParams,
198 View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
199 tmpRect, null);
200 if (res < 0) {
201 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
202 return null;
203 }
204 } catch (RemoteException e) {
205 // Local call.
206 }
207 final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200208 surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700209 navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
210 currentOrientation);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800211 window.setOuter(snapshotSurface);
212 try {
213 session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200214 tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
215 tmpMergedConfiguration, surface);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800216 } catch (RemoteException e) {
217 // Local call.
218 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200219 snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
220 snapshotSurface.drawSnapshot();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800221 return snapshotSurface;
222 }
223
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100224 @VisibleForTesting
225 TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200226 TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
227 int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700228 Rect taskBounds, int currentOrientation) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800229 mService = service;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200230 mHandler = new Handler(mService.mH.getLooper());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800231 mSession = WindowManagerGlobal.getWindowSession();
232 mWindow = window;
233 mSurface = surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200234 mSnapshot = snapshot;
235 mTitle = title;
236 mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
237 mTaskBounds = taskBounds;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200238 mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
239 windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
240 mStatusBarColor = statusBarColor;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700241 mOrientationOnCreation = currentOrientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800242 }
243
244 @Override
245 public void remove() {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200246 synchronized (mService.mWindowMap) {
247 final long now = SystemClock.uptimeMillis();
248 if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
249 mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200250 if (DEBUG_STARTING_WINDOW) {
251 Slog.v(TAG, "Defer removing snapshot surface in " + (now - mShownTime) + "ms");
252 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200253 return;
254 }
255 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800256 try {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200257 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing snapshot surface");
Jorim Jaggi02886a82016-12-06 09:10:06 -0800258 mSession.remove(mWindow);
259 } catch (RemoteException e) {
260 // Local call.
261 }
262 }
263
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200264 @VisibleForTesting
265 void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
266 mFrame.set(frame);
267 mContentInsets.set(contentInsets);
268 mStableInsets.set(stableInsets);
269 mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
270 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200271 mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200272 }
273
274 private void drawSnapshot() {
275 final GraphicBuffer buffer = mSnapshot.getSnapshot();
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200276 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
277 + mSizeMismatch);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200278 if (mSizeMismatch) {
279 // The dimensions of the buffer and the window don't match, so attaching the buffer
280 // will fail. Better create a child window with the exact dimensions and fill the parent
281 // window with the background color!
282 drawSizeMismatchSnapshot(buffer);
283 } else {
284 drawSizeMatchSnapshot(buffer);
285 }
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100286 synchronized (mService.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200287 mShownTime = SystemClock.uptimeMillis();
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100288 mHasDrawn = true;
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100289 }
Jorim Jaggidc9385a2017-05-13 02:00:31 +0200290 reportDrawn();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200291
292 // In case window manager leaks us, make sure we don't retain the snapshot.
293 mSnapshot = null;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200294 }
295
296 private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
297 mSurface.attachAndQueueBuffer(buffer);
298 mSurface.release();
299 }
300
301 private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
302 final SurfaceSession session = new SurfaceSession(mSurface);
303
304 // Keep a reference to it such that it doesn't get destroyed when finalized.
Robert Carre625fcf2017-09-01 12:36:28 -0700305 mChildSurfaceControl = new SurfaceControl.Builder(session)
306 .setName(mTitle + " - task-snapshot-surface")
307 .setSize(buffer.getWidth(), buffer.getHeight())
308 .setFormat(buffer.getFormat())
309 .build();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200310 Surface surface = new Surface();
311 surface.copyFrom(mChildSurfaceControl);
312
313 // Clip off ugly navigation bar.
314 final Rect crop = calculateSnapshotCrop();
315 final Rect frame = calculateSnapshotFrame(crop);
316 SurfaceControl.openTransaction();
317 try {
318 // We can just show the surface here as it will still be hidden as the parent is
319 // still hidden.
320 mChildSurfaceControl.show();
321 mChildSurfaceControl.setWindowCrop(crop);
322 mChildSurfaceControl.setPosition(frame.left, frame.top);
Matthew Ngcb7ac672017-07-21 17:27:42 -0700323
324 // Scale the mismatch dimensions to fill the task bounds
325 final float scale = 1 / mSnapshot.getScale();
326 mChildSurfaceControl.setMatrix(scale, 0, 0, scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200327 } finally {
328 SurfaceControl.closeTransaction();
329 }
330 surface.attachAndQueueBuffer(buffer);
331 surface.release();
332
333 final Canvas c = mSurface.lockCanvas(null);
334 drawBackgroundAndBars(c, frame);
335 mSurface.unlockCanvasAndPost(c);
Jorim Jaggi2f24b652017-01-18 02:17:37 +0100336 mSurface.release();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800337 }
338
Matthew Ngcb7ac672017-07-21 17:27:42 -0700339 /**
340 * Calculates the snapshot crop in snapshot coordinate space.
341 *
342 * @return crop rect in snapshot coordinate space.
343 */
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100344 @VisibleForTesting
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200345 Rect calculateSnapshotCrop() {
346 final Rect rect = new Rect();
347 rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
348 final Rect insets = mSnapshot.getContentInsets();
349
350 // Let's remove all system decorations except the status bar, but only if the task is at the
351 // very top of the screen.
Adrian Roos98a146d2017-11-29 16:39:44 +0100352 final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
Matthew Ngcb7ac672017-07-21 17:27:42 -0700353 rect.inset((int) (insets.left * mSnapshot.getScale()),
Adrian Roos98a146d2017-11-29 16:39:44 +0100354 isTop ? 0 : (int) (insets.top * mSnapshot.getScale()),
Matthew Ngcb7ac672017-07-21 17:27:42 -0700355 (int) (insets.right * mSnapshot.getScale()),
356 (int) (insets.bottom * mSnapshot.getScale()));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200357 return rect;
358 }
359
Matthew Ngcb7ac672017-07-21 17:27:42 -0700360 /**
361 * Calculates the snapshot frame in window coordinate space from crop.
362 *
363 * @param crop rect that is in snapshot coordinate space.
364 */
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200365 @VisibleForTesting
366 Rect calculateSnapshotFrame(Rect crop) {
367 final Rect frame = new Rect(crop);
Matthew Ngcb7ac672017-07-21 17:27:42 -0700368 final float scale = mSnapshot.getScale();
369
370 // Rescale the frame from snapshot to window coordinate space
371 frame.scale(1 / scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200372
373 // By default, offset it to to top/left corner
Matthew Ngcb7ac672017-07-21 17:27:42 -0700374 frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200375
376 // However, we also need to make space for the navigation bar on the left side.
377 final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
378 mContentInsets.left);
379 frame.offset(colorViewLeftInset, 0);
380 return frame;
381 }
382
383 @VisibleForTesting
384 void drawBackgroundAndBars(Canvas c, Rect frame) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200385 final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200386 final boolean fillHorizontally = c.getWidth() > frame.right;
387 final boolean fillVertically = c.getHeight() > frame.bottom;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100388 if (fillHorizontally) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200389 c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
390 c.getWidth(), fillVertically
391 ? frame.bottom
392 : c.getHeight(),
393 mBackgroundPaint);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100394 }
395 if (fillVertically) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200396 c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
397 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200398 mSystemBarBackgroundPainter.drawDecors(c, frame);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100399 }
400
Jorim Jaggi02886a82016-12-06 09:10:06 -0800401 private void reportDrawn() {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800402 try {
403 mSession.finishDrawing(mWindow);
404 } catch (RemoteException e) {
405 // Local call.
406 }
407 }
408
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100409 private static Handler sHandler = new Handler(Looper.getMainLooper()) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800410
411 @Override
412 public void handleMessage(Message msg) {
413 switch (msg.what) {
414 case MSG_REPORT_DRAW:
415 final boolean hasDrawn;
416 final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
417 synchronized (surface.mService.mWindowMap) {
418 hasDrawn = surface.mHasDrawn;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800419 }
420 if (hasDrawn) {
421 surface.reportDrawn();
422 }
423 break;
424 }
425 }
426 };
427
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200428 @VisibleForTesting
429 static class Window extends BaseIWindow {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800430
431 private TaskSnapshotSurface mOuter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700432
Jorim Jaggi02886a82016-12-06 09:10:06 -0800433 public void setOuter(TaskSnapshotSurface outer) {
434 mOuter = outer;
435 }
436
437 @Override
438 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Andrii Kulian44607962017-03-16 11:06:24 -0700439 Rect stableInsets, Rect outsets, boolean reportDraw,
440 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
441 boolean alwaysConsumeNavBar, int displayId) {
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700442 if (mergedConfiguration != null && mOuter != null
443 && mOuter.mOrientationOnCreation
444 != mergedConfiguration.getMergedConfiguration().orientation) {
445
446 // The orientation of the screen is changing. We better remove the snapshot ASAP as
447 // we are going to wait on the new window in any case to unfreeze the screen, and
448 // the starting window is not needed anymore.
449 sHandler.post(mOuter::remove);
450 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800451 if (reportDraw) {
452 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
453 }
454 }
455 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200456
457 /**
458 * Helper class to draw the background of the system bars in regions the task snapshot isn't
459 * filling the window.
460 */
461 static class SystemBarBackgroundPainter {
462
463 private final Rect mContentInsets = new Rect();
464 private final Rect mStableInsets = new Rect();
465 private final Paint mStatusBarPaint = new Paint();
466 private final Paint mNavigationBarPaint = new Paint();
467 private final int mStatusBarColor;
468 private final int mNavigationBarColor;
469 private final int mWindowFlags;
470 private final int mWindowPrivateFlags;
471 private final int mSysUiVis;
472
473 SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
474 int statusBarColor, int navigationBarColor) {
475 mWindowFlags = windowFlags;
476 mWindowPrivateFlags = windowPrivateFlags;
477 mSysUiVis = sysUiVis;
478 final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
479 mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
480 context.getColor(R.color.system_bar_background_semi_transparent),
481 statusBarColor);
482 mNavigationBarColor = navigationBarColor;
483 mStatusBarPaint.setColor(mStatusBarColor);
484 mNavigationBarPaint.setColor(navigationBarColor);
485 }
486
487 void setInsets(Rect contentInsets, Rect stableInsets) {
488 mContentInsets.set(contentInsets);
489 mStableInsets.set(stableInsets);
490 }
491
492 int getStatusBarColorViewHeight() {
493 final boolean forceStatusBarBackground =
494 (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
495 if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
496 mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
497 return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
498 } else {
499 return 0;
500 }
501 }
502
503 private boolean isNavigationBarColorViewVisible() {
504 return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
505 mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
506 }
507
508 void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
509 drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
510 drawNavigationBarBackground(c);
511 }
512
513 @VisibleForTesting
514 void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
515 int statusBarHeight) {
516 if (statusBarHeight > 0
517 && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
518 final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
519 mContentInsets.right);
520 final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
521 c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
522 }
523 }
524
525 @VisibleForTesting
526 void drawNavigationBarBackground(Canvas c) {
527 final Rect navigationBarRect = new Rect();
528 getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
529 navigationBarRect);
530 final boolean visible = isNavigationBarColorViewVisible();
531 if (visible && !navigationBarRect.isEmpty()) {
532 c.drawRect(navigationBarRect, mNavigationBarPaint);
533 }
534 }
535 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800536}