blob: 3ce090ace7b30c4e8c21a57fbb30d0151abd0079 [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.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 Jaggie4b0f282017-05-17 15:10:29 +020042import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
Jorim Jaggi02886a82016-12-06 09:10:06 -080043import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
44import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
45
Jorim Jaggid635a4a2017-05-03 15:21:26 +020046import android.annotation.Nullable;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010047import android.app.ActivityManager.TaskDescription;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020048import android.app.ActivityManager.TaskSnapshot;
Jorim Jaggid635a4a2017-05-03 15:21:26 +020049import android.app.ActivityThread;
50import android.content.Context;
Jorim Jaggi02886a82016-12-06 09:10:06 -080051import android.graphics.Canvas;
52import android.graphics.GraphicBuffer;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010053import android.graphics.Paint;
Jorim Jaggi02886a82016-12-06 09:10:06 -080054import android.graphics.Rect;
55import android.os.Handler;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010056import android.os.Looper;
Jorim Jaggi02886a82016-12-06 09:10:06 -080057import android.os.Message;
58import android.os.RemoteException;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020059import android.os.SystemClock;
Andrii Kulian44607962017-03-16 11:06:24 -070060import android.util.MergedConfiguration;
Jorim Jaggi02886a82016-12-06 09:10:06 -080061import android.util.Slog;
Jorim Jaggi02886a82016-12-06 09:10:06 -080062import android.view.IWindowSession;
63import android.view.Surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020064import android.view.SurfaceControl;
65import android.view.SurfaceSession;
Jorim Jaggi02886a82016-12-06 09:10:06 -080066import android.view.View;
67import android.view.ViewGroup.LayoutParams;
68import android.view.WindowManager;
69import android.view.WindowManagerGlobal;
70import android.view.WindowManagerPolicy.StartingSurface;
71
Jorim Jaggi30d64f32017-04-07 16:33:17 +020072import com.android.internal.R;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010073import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020074import com.android.internal.policy.DecorView;
Jorim Jaggi02886a82016-12-06 09:10:06 -080075import com.android.internal.view.BaseIWindow;
76
77/**
78 * This class represents a starting window that shows a snapshot.
79 * <p>
80 * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
81 */
82class TaskSnapshotSurface implements StartingSurface {
83
Jorim Jaggi30d64f32017-04-07 16:33:17 +020084 private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
85
86 /**
87 * When creating the starting window, we use the exact same layout flags such that we end up
88 * with a window with the exact same dimensions etc. However, these flags are not used in layout
89 * and might cause other side effects so we exclude them.
90 */
91 private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
92 | FLAG_NOT_TOUCHABLE
93 | FLAG_NOT_TOUCH_MODAL
94 | FLAG_ALT_FOCUSABLE_IM
95 | FLAG_NOT_FOCUSABLE
96 | FLAG_HARDWARE_ACCELERATED
97 | FLAG_IGNORE_CHEEK_PRESSES
98 | FLAG_LOCAL_FOCUS_MODE
99 | FLAG_SLIPPERY
100 | FLAG_WATCH_OUTSIDE_TOUCH
101 | FLAG_SPLIT_TOUCH
102 | FLAG_SCALED
103 | FLAG_SECURE;
104
Jorim Jaggid2616322017-06-07 12:38:19 -0700105 private static final int PRIVATE_FLAG_INHERITS = PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
106
Jorim Jaggi02886a82016-12-06 09:10:06 -0800107 private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
108 private static final int MSG_REPORT_DRAW = 0;
109 private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
110 private final Window mWindow;
111 private final Surface mSurface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200112 private SurfaceControl mChildSurfaceControl;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800113 private final IWindowSession mSession;
114 private final WindowManagerService mService;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200115 private final Rect mTaskBounds;
116 private final Rect mStableInsets = new Rect();
117 private final Rect mContentInsets = new Rect();
118 private final Rect mFrame = new Rect();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200119 private TaskSnapshot mSnapshot;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200120 private final CharSequence mTitle;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800121 private boolean mHasDrawn;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200122 private long mShownTime;
123 private final Handler mHandler;
124 private boolean mSizeMismatch;
125 private final Paint mBackgroundPaint = new Paint();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200126 private final int mStatusBarColor;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200127 @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700128 private final int mOrientationOnCreation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800129
130 static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200131 TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800132
133 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
134 final Window window = new Window();
135 final IWindowSession session = WindowManagerGlobal.getWindowSession();
136 window.setSession(session);
137 final Surface surface = new Surface();
138 final Rect tmpRect = new Rect();
139 final Rect tmpFrame = new Rect();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200140 final Rect taskBounds;
141 final Rect tmpContentInsets = new Rect();
142 final Rect tmpStableInsets = new Rect();
Andrii Kulian44607962017-03-16 11:06:24 -0700143 final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200144 int backgroundColor = WHITE;
145 int statusBarColor = 0;
146 int navigationBarColor = 0;
147 final int sysUiVis;
148 final int windowFlags;
149 final int windowPrivateFlags;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700150 final int currentOrientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800151 synchronized (service.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200152 final WindowState mainWindow = token.findMainWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200153 final Task task = token.getTask();
154 if (task == null) {
155 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for token="
156 + token);
157 return null;
158 }
159 final AppWindowToken topFullscreenToken = token.getTask().getTopFullscreenAppToken();
160 if (topFullscreenToken == null) {
161 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
162 + task);
163 return null;
164 }
Jorim Jaggi87fdbcb2017-08-17 13:41:11 +0200165 final WindowState topFullscreenWindow = topFullscreenToken.getTopFullscreenWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200166 if (mainWindow == null || topFullscreenWindow == null) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200167 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
168 + token);
169 return null;
170 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200171 sysUiVis = topFullscreenWindow.getSystemUiVisibility();
172 windowFlags = topFullscreenWindow.getAttrs().flags;
173 windowPrivateFlags = topFullscreenWindow.getAttrs().privateFlags;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200174
Winson Chungbe9be7f2017-06-28 10:55:22 -0700175 layoutParams.dimAmount = mainWindow.getAttrs().dimAmount;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800176 layoutParams.type = TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200177 layoutParams.format = snapshot.getSnapshot().getFormat();
178 layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
Jorim Jaggi02886a82016-12-06 09:10:06 -0800179 | FLAG_NOT_FOCUSABLE
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200180 | FLAG_NOT_TOUCHABLE;
Wale Ogunwale01ad4342017-06-30 07:07:01 -0700181 layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800182 layoutParams.token = token.token;
183 layoutParams.width = LayoutParams.MATCH_PARENT;
184 layoutParams.height = LayoutParams.MATCH_PARENT;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200185 layoutParams.systemUiVisibility = sysUiVis;
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200186 layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
Bryce Lee6d410262017-02-28 15:30:17 -0800187
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200188 final TaskDescription taskDescription = task.getTaskDescription();
189 if (taskDescription != null) {
190 backgroundColor = taskDescription.getBackgroundColor();
191 statusBarColor = taskDescription.getStatusBarColor();
192 navigationBarColor = taskDescription.getNavigationBarColor();
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100193 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200194 taskBounds = new Rect();
195 task.getBounds(taskBounds);
196 currentOrientation = topFullscreenWindow.getConfiguration().orientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800197 }
198 try {
199 final int res = session.addToDisplay(window, window.mSeq, layoutParams,
200 View.VISIBLE, token.getDisplayContent().getDisplayId(), tmpRect, tmpRect,
201 tmpRect, null);
202 if (res < 0) {
203 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
204 return null;
205 }
206 } catch (RemoteException e) {
207 // Local call.
208 }
209 final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200210 surface, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700211 navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
212 currentOrientation);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800213 window.setOuter(snapshotSurface);
214 try {
215 session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, tmpFrame,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200216 tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
217 tmpMergedConfiguration, surface);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800218 } catch (RemoteException e) {
219 // Local call.
220 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200221 snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
222 snapshotSurface.drawSnapshot();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800223 return snapshotSurface;
224 }
225
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100226 @VisibleForTesting
227 TaskSnapshotSurface(WindowManagerService service, Window window, Surface surface,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200228 TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
229 int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700230 Rect taskBounds, int currentOrientation) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800231 mService = service;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200232 mHandler = new Handler(mService.mH.getLooper());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800233 mSession = WindowManagerGlobal.getWindowSession();
234 mWindow = window;
235 mSurface = surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200236 mSnapshot = snapshot;
237 mTitle = title;
238 mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
239 mTaskBounds = taskBounds;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200240 mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
241 windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
242 mStatusBarColor = statusBarColor;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700243 mOrientationOnCreation = currentOrientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800244 }
245
246 @Override
247 public void remove() {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200248 synchronized (mService.mWindowMap) {
249 final long now = SystemClock.uptimeMillis();
250 if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
251 mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200252 if (DEBUG_STARTING_WINDOW) {
253 Slog.v(TAG, "Defer removing snapshot surface in " + (now - mShownTime) + "ms");
254 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200255 return;
256 }
257 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800258 try {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200259 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing snapshot surface");
Jorim Jaggi02886a82016-12-06 09:10:06 -0800260 mSession.remove(mWindow);
261 } catch (RemoteException e) {
262 // Local call.
263 }
264 }
265
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200266 @VisibleForTesting
267 void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
268 mFrame.set(frame);
269 mContentInsets.set(contentInsets);
270 mStableInsets.set(stableInsets);
271 mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
272 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200273 mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200274 }
275
276 private void drawSnapshot() {
277 final GraphicBuffer buffer = mSnapshot.getSnapshot();
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200278 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
279 + mSizeMismatch);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200280 if (mSizeMismatch) {
281 // The dimensions of the buffer and the window don't match, so attaching the buffer
282 // will fail. Better create a child window with the exact dimensions and fill the parent
283 // window with the background color!
284 drawSizeMismatchSnapshot(buffer);
285 } else {
286 drawSizeMatchSnapshot(buffer);
287 }
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100288 synchronized (mService.mWindowMap) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200289 mShownTime = SystemClock.uptimeMillis();
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100290 mHasDrawn = true;
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100291 }
Jorim Jaggidc9385a2017-05-13 02:00:31 +0200292 reportDrawn();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200293
294 // In case window manager leaks us, make sure we don't retain the snapshot.
295 mSnapshot = null;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200296 }
297
298 private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
299 mSurface.attachAndQueueBuffer(buffer);
300 mSurface.release();
301 }
302
303 private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
304 final SurfaceSession session = new SurfaceSession(mSurface);
305
306 // Keep a reference to it such that it doesn't get destroyed when finalized.
Robert Carre625fcf2017-09-01 12:36:28 -0700307 mChildSurfaceControl = new SurfaceControl.Builder(session)
308 .setName(mTitle + " - task-snapshot-surface")
309 .setSize(buffer.getWidth(), buffer.getHeight())
310 .setFormat(buffer.getFormat())
311 .build();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200312 Surface surface = new Surface();
313 surface.copyFrom(mChildSurfaceControl);
314
315 // Clip off ugly navigation bar.
316 final Rect crop = calculateSnapshotCrop();
317 final Rect frame = calculateSnapshotFrame(crop);
318 SurfaceControl.openTransaction();
319 try {
320 // We can just show the surface here as it will still be hidden as the parent is
321 // still hidden.
322 mChildSurfaceControl.show();
323 mChildSurfaceControl.setWindowCrop(crop);
324 mChildSurfaceControl.setPosition(frame.left, frame.top);
Matthew Ngcb7ac672017-07-21 17:27:42 -0700325
326 // Scale the mismatch dimensions to fill the task bounds
327 final float scale = 1 / mSnapshot.getScale();
328 mChildSurfaceControl.setMatrix(scale, 0, 0, scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200329 } finally {
330 SurfaceControl.closeTransaction();
331 }
332 surface.attachAndQueueBuffer(buffer);
333 surface.release();
334
335 final Canvas c = mSurface.lockCanvas(null);
336 drawBackgroundAndBars(c, frame);
337 mSurface.unlockCanvasAndPost(c);
Jorim Jaggi2f24b652017-01-18 02:17:37 +0100338 mSurface.release();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800339 }
340
Matthew Ngcb7ac672017-07-21 17:27:42 -0700341 /**
342 * Calculates the snapshot crop in snapshot coordinate space.
343 *
344 * @return crop rect in snapshot coordinate space.
345 */
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100346 @VisibleForTesting
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200347 Rect calculateSnapshotCrop() {
348 final Rect rect = new Rect();
349 rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
350 final Rect insets = mSnapshot.getContentInsets();
351
352 // Let's remove all system decorations except the status bar, but only if the task is at the
353 // very top of the screen.
Matthew Ngcb7ac672017-07-21 17:27:42 -0700354 rect.inset((int) (insets.left * mSnapshot.getScale()),
355 mTaskBounds.top != 0 ? (int) (insets.top * mSnapshot.getScale()) : 0,
356 (int) (insets.right * mSnapshot.getScale()),
357 (int) (insets.bottom * mSnapshot.getScale()));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200358 return rect;
359 }
360
Matthew Ngcb7ac672017-07-21 17:27:42 -0700361 /**
362 * Calculates the snapshot frame in window coordinate space from crop.
363 *
364 * @param crop rect that is in snapshot coordinate space.
365 */
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200366 @VisibleForTesting
367 Rect calculateSnapshotFrame(Rect crop) {
368 final Rect frame = new Rect(crop);
Matthew Ngcb7ac672017-07-21 17:27:42 -0700369 final float scale = mSnapshot.getScale();
370
371 // Rescale the frame from snapshot to window coordinate space
372 frame.scale(1 / scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200373
374 // By default, offset it to to top/left corner
Matthew Ngcb7ac672017-07-21 17:27:42 -0700375 frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200376
377 // However, we also need to make space for the navigation bar on the left side.
378 final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
379 mContentInsets.left);
380 frame.offset(colorViewLeftInset, 0);
381 return frame;
382 }
383
384 @VisibleForTesting
385 void drawBackgroundAndBars(Canvas c, Rect frame) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200386 final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200387 final boolean fillHorizontally = c.getWidth() > frame.right;
388 final boolean fillVertically = c.getHeight() > frame.bottom;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100389 if (fillHorizontally) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200390 c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
391 c.getWidth(), fillVertically
392 ? frame.bottom
393 : c.getHeight(),
394 mBackgroundPaint);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100395 }
396 if (fillVertically) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200397 c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
398 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200399 mSystemBarBackgroundPainter.drawDecors(c, frame);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100400 }
401
Jorim Jaggi02886a82016-12-06 09:10:06 -0800402 private void reportDrawn() {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800403 try {
404 mSession.finishDrawing(mWindow);
405 } catch (RemoteException e) {
406 // Local call.
407 }
408 }
409
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100410 private static Handler sHandler = new Handler(Looper.getMainLooper()) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800411
412 @Override
413 public void handleMessage(Message msg) {
414 switch (msg.what) {
415 case MSG_REPORT_DRAW:
416 final boolean hasDrawn;
417 final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
418 synchronized (surface.mService.mWindowMap) {
419 hasDrawn = surface.mHasDrawn;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800420 }
421 if (hasDrawn) {
422 surface.reportDrawn();
423 }
424 break;
425 }
426 }
427 };
428
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200429 @VisibleForTesting
430 static class Window extends BaseIWindow {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800431
432 private TaskSnapshotSurface mOuter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700433
Jorim Jaggi02886a82016-12-06 09:10:06 -0800434 public void setOuter(TaskSnapshotSurface outer) {
435 mOuter = outer;
436 }
437
438 @Override
439 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Andrii Kulian44607962017-03-16 11:06:24 -0700440 Rect stableInsets, Rect outsets, boolean reportDraw,
441 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
442 boolean alwaysConsumeNavBar, int displayId) {
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700443 if (mergedConfiguration != null && mOuter != null
444 && mOuter.mOrientationOnCreation
445 != mergedConfiguration.getMergedConfiguration().orientation) {
446
447 // The orientation of the screen is changing. We better remove the snapshot ASAP as
448 // we are going to wait on the new window in any case to unfreeze the screen, and
449 // the starting window is not needed anymore.
450 sHandler.post(mOuter::remove);
451 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800452 if (reportDraw) {
453 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
454 }
455 }
456 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200457
458 /**
459 * Helper class to draw the background of the system bars in regions the task snapshot isn't
460 * filling the window.
461 */
462 static class SystemBarBackgroundPainter {
463
464 private final Rect mContentInsets = new Rect();
465 private final Rect mStableInsets = new Rect();
466 private final Paint mStatusBarPaint = new Paint();
467 private final Paint mNavigationBarPaint = new Paint();
468 private final int mStatusBarColor;
469 private final int mNavigationBarColor;
470 private final int mWindowFlags;
471 private final int mWindowPrivateFlags;
472 private final int mSysUiVis;
473
474 SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
475 int statusBarColor, int navigationBarColor) {
476 mWindowFlags = windowFlags;
477 mWindowPrivateFlags = windowPrivateFlags;
478 mSysUiVis = sysUiVis;
479 final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
480 mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
481 context.getColor(R.color.system_bar_background_semi_transparent),
482 statusBarColor);
483 mNavigationBarColor = navigationBarColor;
484 mStatusBarPaint.setColor(mStatusBarColor);
485 mNavigationBarPaint.setColor(navigationBarColor);
486 }
487
488 void setInsets(Rect contentInsets, Rect stableInsets) {
489 mContentInsets.set(contentInsets);
490 mStableInsets.set(stableInsets);
491 }
492
493 int getStatusBarColorViewHeight() {
494 final boolean forceStatusBarBackground =
495 (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
496 if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
497 mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
498 return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
499 } else {
500 return 0;
501 }
502 }
503
504 private boolean isNavigationBarColorViewVisible() {
505 return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
506 mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
507 }
508
509 void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
510 drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
511 drawNavigationBarBackground(c);
512 }
513
514 @VisibleForTesting
515 void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
516 int statusBarHeight) {
517 if (statusBarHeight > 0
518 && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
519 final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
520 mContentInsets.right);
521 final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
522 c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
523 }
524 }
525
526 @VisibleForTesting
527 void drawNavigationBarBackground(Canvas c) {
528 final Rect navigationBarRect = new Rect();
529 getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
530 navigationBarRect);
531 final boolean visible = isNavigationBarColorViewVisible();
532 if (visible && !navigationBarRect.isEmpty()) {
533 c.drawRect(navigationBarRect, mNavigationBarPaint);
534 }
535 }
536 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800537}