blob: 938c8b452e29ee2f5c75e6580b20af4e69606ab1 [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;
Vishnu Naire86bd982018-11-28 13:23:17 -080035
Jorim Jaggi30d64f32017-04-07 16:33:17 +020036import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
37import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
38import static com.android.internal.policy.DecorView.getColorViewLeftInset;
39import static com.android.internal.policy.DecorView.getColorViewTopInset;
40import static com.android.internal.policy.DecorView.getNavigationBarRect;
Jorim Jaggie4b0f282017-05-17 15:10:29 +020041import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
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;
Winson Chung51f42d22018-02-01 14:59:38 -080051import android.graphics.Color;
Jorim Jaggi02886a82016-12-06 09:10:06 -080052import 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;
Adrian Roos5c6b6222017-11-07 17:36:10 +010062import android.view.DisplayCutout;
Jorim Jaggi02886a82016-12-06 09:10:06 -080063import android.view.IWindowSession;
Chavi Weingarten6ef9cc62019-02-07 16:28:45 +000064import android.view.InsetsState;
Jorim Jaggi02886a82016-12-06 09:10:06 -080065import android.view.Surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020066import android.view.SurfaceControl;
67import android.view.SurfaceSession;
Jorim Jaggi02886a82016-12-06 09:10:06 -080068import android.view.View;
69import android.view.ViewGroup.LayoutParams;
70import android.view.WindowManager;
71import android.view.WindowManagerGlobal;
Jorim Jaggi02886a82016-12-06 09:10:06 -080072
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;
Adrian Roose99bc052017-11-20 17:55:31 +010077import com.android.server.policy.WindowManagerPolicy.StartingSurface;
Jorim Jaggi02886a82016-12-06 09:10:06 -080078
79/**
80 * This class represents a starting window that shows a snapshot.
81 * <p>
82 * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
83 */
84class TaskSnapshotSurface implements StartingSurface {
85
Jorim Jaggi30d64f32017-04-07 16:33:17 +020086 private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
87
88 /**
89 * When creating the starting window, we use the exact same layout flags such that we end up
90 * with a window with the exact same dimensions etc. However, these flags are not used in layout
91 * and might cause other side effects so we exclude them.
92 */
93 private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
94 | FLAG_NOT_TOUCHABLE
95 | FLAG_NOT_TOUCH_MODAL
96 | FLAG_ALT_FOCUSABLE_IM
97 | FLAG_NOT_FOCUSABLE
98 | FLAG_HARDWARE_ACCELERATED
99 | FLAG_IGNORE_CHEEK_PRESSES
100 | FLAG_LOCAL_FOCUS_MODE
101 | FLAG_SLIPPERY
102 | FLAG_WATCH_OUTSIDE_TOUCH
103 | FLAG_SPLIT_TOUCH
104 | FLAG_SCALED
105 | FLAG_SECURE;
106
Jorim Jaggid2616322017-06-07 12:38:19 -0700107 private static final int PRIVATE_FLAG_INHERITS = PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
108
Jorim Jaggi02886a82016-12-06 09:10:06 -0800109 private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
110 private static final int MSG_REPORT_DRAW = 0;
111 private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
112 private final Window mWindow;
113 private final Surface mSurface;
Robert Carr5fea55b2018-12-10 13:05:52 -0800114 private SurfaceControl mSurfaceControl;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200115 private SurfaceControl mChildSurfaceControl;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800116 private final IWindowSession mSession;
117 private final WindowManagerService mService;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200118 private final Rect mTaskBounds;
119 private final Rect mStableInsets = new Rect();
120 private final Rect mContentInsets = new Rect();
121 private final Rect mFrame = new Rect();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200122 private TaskSnapshot mSnapshot;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200123 private final CharSequence mTitle;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800124 private boolean mHasDrawn;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200125 private long mShownTime;
126 private final Handler mHandler;
127 private boolean mSizeMismatch;
128 private final Paint mBackgroundPaint = new Paint();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200129 private final int mStatusBarColor;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200130 @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700131 private final int mOrientationOnCreation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800132
133 static TaskSnapshotSurface create(WindowManagerService service, AppWindowToken token,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200134 TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800135
136 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
137 final Window window = new Window();
138 final IWindowSession session = WindowManagerGlobal.getWindowSession();
139 window.setSession(session);
Robert Carr5fea55b2018-12-10 13:05:52 -0800140 final SurfaceControl surfaceControl = new SurfaceControl();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800141 final Rect tmpRect = new Rect();
Adrian Roos5c6b6222017-11-07 17:36:10 +0100142 final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800143 final Rect tmpFrame = new Rect();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200144 final Rect taskBounds;
145 final Rect tmpContentInsets = new Rect();
146 final Rect tmpStableInsets = new Rect();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200147 final InsetsState mTmpInsetsState = new InsetsState();
Andrii Kulian44607962017-03-16 11:06:24 -0700148 final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200149 int backgroundColor = WHITE;
150 int statusBarColor = 0;
151 int navigationBarColor = 0;
152 final int sysUiVis;
153 final int windowFlags;
154 final int windowPrivateFlags;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700155 final int currentOrientation;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700156 synchronized (service.mGlobalLock) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200157 final WindowState mainWindow = token.findMainWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200158 final Task task = token.getTask();
159 if (task == null) {
160 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for token="
161 + token);
162 return null;
163 }
164 final AppWindowToken topFullscreenToken = token.getTask().getTopFullscreenAppToken();
165 if (topFullscreenToken == null) {
166 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
167 + task);
168 return null;
169 }
Jorim Jaggi87fdbcb2017-08-17 13:41:11 +0200170 final WindowState topFullscreenWindow = topFullscreenToken.getTopFullscreenWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200171 if (mainWindow == null || topFullscreenWindow == null) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200172 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for token="
173 + token);
174 return null;
175 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200176 sysUiVis = topFullscreenWindow.getSystemUiVisibility();
177 windowFlags = topFullscreenWindow.getAttrs().flags;
178 windowPrivateFlags = topFullscreenWindow.getAttrs().privateFlags;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200179
Jorim Jaggi90b3c472018-04-06 16:02:07 +0200180 layoutParams.packageName = mainWindow.getAttrs().packageName;
181 layoutParams.windowAnimations = mainWindow.getAttrs().windowAnimations;
Winson Chungbe9be7f2017-06-28 10:55:22 -0700182 layoutParams.dimAmount = mainWindow.getAttrs().dimAmount;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800183 layoutParams.type = TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200184 layoutParams.format = snapshot.getSnapshot().getFormat();
185 layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
Jorim Jaggi02886a82016-12-06 09:10:06 -0800186 | FLAG_NOT_FOCUSABLE
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200187 | FLAG_NOT_TOUCHABLE;
Wale Ogunwale01ad4342017-06-30 07:07:01 -0700188 layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800189 layoutParams.token = token.token;
190 layoutParams.width = LayoutParams.MATCH_PARENT;
191 layoutParams.height = LayoutParams.MATCH_PARENT;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200192 layoutParams.systemUiVisibility = sysUiVis;
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200193 layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
Bryce Lee6d410262017-02-28 15:30:17 -0800194
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200195 final TaskDescription taskDescription = task.getTaskDescription();
196 if (taskDescription != null) {
197 backgroundColor = taskDescription.getBackgroundColor();
198 statusBarColor = taskDescription.getStatusBarColor();
199 navigationBarColor = taskDescription.getNavigationBarColor();
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100200 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200201 taskBounds = new Rect();
202 task.getBounds(taskBounds);
203 currentOrientation = topFullscreenWindow.getConfiguration().orientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800204 }
205 try {
206 final int res = session.addToDisplay(window, window.mSeq, layoutParams,
Adrian Roos9e370f22018-03-06 18:19:45 +0100207 View.GONE, token.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect,
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200208 tmpRect, tmpCutout, null, mTmpInsetsState);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800209 if (res < 0) {
210 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
211 return null;
212 }
213 } catch (RemoteException e) {
214 // Local call.
215 }
216 final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
Robert Carr5fea55b2018-12-10 13:05:52 -0800217 surfaceControl, snapshot, layoutParams.getTitle(), backgroundColor, statusBarColor,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700218 navigationBarColor, sysUiVis, windowFlags, windowPrivateFlags, taskBounds,
219 currentOrientation);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800220 window.setOuter(snapshotSurface);
221 try {
chaviwbe43ac82018-04-04 15:14:49 -0700222 session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
223 tmpFrame, tmpRect, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect, tmpRect,
Robert Carr5fea55b2018-12-10 13:05:52 -0800224 tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800225 } catch (RemoteException e) {
226 // Local call.
227 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200228 snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
229 snapshotSurface.drawSnapshot();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800230 return snapshotSurface;
231 }
232
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100233 @VisibleForTesting
Robert Carr5fea55b2018-12-10 13:05:52 -0800234 TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200235 TaskSnapshot snapshot, CharSequence title, int backgroundColor, int statusBarColor,
236 int navigationBarColor, int sysUiVis, int windowFlags, int windowPrivateFlags,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700237 Rect taskBounds, int currentOrientation) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800238 mService = service;
Robert Carr5fea55b2018-12-10 13:05:52 -0800239 mSurface = new Surface();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200240 mHandler = new Handler(mService.mH.getLooper());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800241 mSession = WindowManagerGlobal.getWindowSession();
242 mWindow = window;
Robert Carr5fea55b2018-12-10 13:05:52 -0800243 mSurfaceControl = surfaceControl;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200244 mSnapshot = snapshot;
245 mTitle = title;
246 mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
247 mTaskBounds = taskBounds;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200248 mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
249 windowPrivateFlags, sysUiVis, statusBarColor, navigationBarColor);
250 mStatusBarColor = statusBarColor;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700251 mOrientationOnCreation = currentOrientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800252 }
253
254 @Override
255 public void remove() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700256 synchronized (mService.mGlobalLock) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200257 final long now = SystemClock.uptimeMillis();
258 if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
259 mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200260 if (DEBUG_STARTING_WINDOW) {
261 Slog.v(TAG, "Defer removing snapshot surface in " + (now - mShownTime) + "ms");
262 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200263 return;
264 }
265 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800266 try {
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200267 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Removing snapshot surface");
Jorim Jaggi02886a82016-12-06 09:10:06 -0800268 mSession.remove(mWindow);
269 } catch (RemoteException e) {
270 // Local call.
271 }
272 }
273
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200274 @VisibleForTesting
275 void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
276 mFrame.set(frame);
277 mContentInsets.set(contentInsets);
278 mStableInsets.set(stableInsets);
279 mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
280 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200281 mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200282 }
283
284 private void drawSnapshot() {
285 final GraphicBuffer buffer = mSnapshot.getSnapshot();
Robert Carr5fea55b2018-12-10 13:05:52 -0800286 mSurface.copyFrom(mSurfaceControl);
287
Jorim Jaggie4b0f282017-05-17 15:10:29 +0200288 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Drawing snapshot surface sizeMismatch="
289 + mSizeMismatch);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200290 if (mSizeMismatch) {
291 // The dimensions of the buffer and the window don't match, so attaching the buffer
292 // will fail. Better create a child window with the exact dimensions and fill the parent
293 // window with the background color!
294 drawSizeMismatchSnapshot(buffer);
295 } else {
296 drawSizeMatchSnapshot(buffer);
297 }
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700298 synchronized (mService.mGlobalLock) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200299 mShownTime = SystemClock.uptimeMillis();
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100300 mHasDrawn = true;
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100301 }
Jorim Jaggidc9385a2017-05-13 02:00:31 +0200302 reportDrawn();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200303
304 // In case window manager leaks us, make sure we don't retain the snapshot.
305 mSnapshot = null;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200306 }
307
308 private void drawSizeMatchSnapshot(GraphicBuffer buffer) {
309 mSurface.attachAndQueueBuffer(buffer);
310 mSurface.release();
311 }
312
313 private void drawSizeMismatchSnapshot(GraphicBuffer buffer) {
Shibin George9696bd32018-02-26 20:29:44 +0530314 if (!mSurface.isValid()) {
315 throw new IllegalStateException("mSurface does not hold a valid surface.");
316 }
Robert Carr5fea55b2018-12-10 13:05:52 -0800317 final SurfaceSession session = new SurfaceSession();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200318
319 // Keep a reference to it such that it doesn't get destroyed when finalized.
Robert Carre625fcf2017-09-01 12:36:28 -0700320 mChildSurfaceControl = new SurfaceControl.Builder(session)
321 .setName(mTitle + " - task-snapshot-surface")
Vishnu Naire86bd982018-11-28 13:23:17 -0800322 .setBufferSize(buffer.getWidth(), buffer.getHeight())
Robert Carre625fcf2017-09-01 12:36:28 -0700323 .setFormat(buffer.getFormat())
Robert Carr5fea55b2018-12-10 13:05:52 -0800324 .setParent(mSurfaceControl)
Robert Carre625fcf2017-09-01 12:36:28 -0700325 .build();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200326 Surface surface = new Surface();
327 surface.copyFrom(mChildSurfaceControl);
328
329 // Clip off ugly navigation bar.
330 final Rect crop = calculateSnapshotCrop();
331 final Rect frame = calculateSnapshotFrame(crop);
332 SurfaceControl.openTransaction();
333 try {
334 // We can just show the surface here as it will still be hidden as the parent is
335 // still hidden.
336 mChildSurfaceControl.show();
337 mChildSurfaceControl.setWindowCrop(crop);
338 mChildSurfaceControl.setPosition(frame.left, frame.top);
Matthew Ngcb7ac672017-07-21 17:27:42 -0700339
340 // Scale the mismatch dimensions to fill the task bounds
341 final float scale = 1 / mSnapshot.getScale();
342 mChildSurfaceControl.setMatrix(scale, 0, 0, scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200343 } finally {
344 SurfaceControl.closeTransaction();
345 }
346 surface.attachAndQueueBuffer(buffer);
347 surface.release();
348
349 final Canvas c = mSurface.lockCanvas(null);
350 drawBackgroundAndBars(c, frame);
351 mSurface.unlockCanvasAndPost(c);
Jorim Jaggi2f24b652017-01-18 02:17:37 +0100352 mSurface.release();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800353 }
354
Matthew Ngcb7ac672017-07-21 17:27:42 -0700355 /**
356 * Calculates the snapshot crop in snapshot coordinate space.
357 *
358 * @return crop rect in snapshot coordinate space.
359 */
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100360 @VisibleForTesting
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200361 Rect calculateSnapshotCrop() {
362 final Rect rect = new Rect();
363 rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
364 final Rect insets = mSnapshot.getContentInsets();
365
366 // Let's remove all system decorations except the status bar, but only if the task is at the
367 // very top of the screen.
Adrian Roos98a146d2017-11-29 16:39:44 +0100368 final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
Matthew Ngcb7ac672017-07-21 17:27:42 -0700369 rect.inset((int) (insets.left * mSnapshot.getScale()),
Adrian Roos98a146d2017-11-29 16:39:44 +0100370 isTop ? 0 : (int) (insets.top * mSnapshot.getScale()),
Matthew Ngcb7ac672017-07-21 17:27:42 -0700371 (int) (insets.right * mSnapshot.getScale()),
372 (int) (insets.bottom * mSnapshot.getScale()));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200373 return rect;
374 }
375
Matthew Ngcb7ac672017-07-21 17:27:42 -0700376 /**
377 * Calculates the snapshot frame in window coordinate space from crop.
378 *
379 * @param crop rect that is in snapshot coordinate space.
380 */
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200381 @VisibleForTesting
382 Rect calculateSnapshotFrame(Rect crop) {
383 final Rect frame = new Rect(crop);
Matthew Ngcb7ac672017-07-21 17:27:42 -0700384 final float scale = mSnapshot.getScale();
385
386 // Rescale the frame from snapshot to window coordinate space
387 frame.scale(1 / scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200388
389 // By default, offset it to to top/left corner
Matthew Ngcb7ac672017-07-21 17:27:42 -0700390 frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200391
392 // However, we also need to make space for the navigation bar on the left side.
393 final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
394 mContentInsets.left);
395 frame.offset(colorViewLeftInset, 0);
396 return frame;
397 }
398
399 @VisibleForTesting
400 void drawBackgroundAndBars(Canvas c, Rect frame) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200401 final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200402 final boolean fillHorizontally = c.getWidth() > frame.right;
403 final boolean fillVertically = c.getHeight() > frame.bottom;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100404 if (fillHorizontally) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200405 c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
406 c.getWidth(), fillVertically
407 ? frame.bottom
408 : c.getHeight(),
409 mBackgroundPaint);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100410 }
411 if (fillVertically) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200412 c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
413 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200414 mSystemBarBackgroundPainter.drawDecors(c, frame);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100415 }
416
Jorim Jaggi02886a82016-12-06 09:10:06 -0800417 private void reportDrawn() {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800418 try {
419 mSession.finishDrawing(mWindow);
420 } catch (RemoteException e) {
421 // Local call.
422 }
423 }
424
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100425 private static Handler sHandler = new Handler(Looper.getMainLooper()) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800426
427 @Override
428 public void handleMessage(Message msg) {
429 switch (msg.what) {
430 case MSG_REPORT_DRAW:
431 final boolean hasDrawn;
432 final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700433 synchronized (surface.mService.mGlobalLock) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800434 hasDrawn = surface.mHasDrawn;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800435 }
436 if (hasDrawn) {
437 surface.reportDrawn();
438 }
439 break;
440 }
441 }
442 };
443
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200444 @VisibleForTesting
445 static class Window extends BaseIWindow {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800446
447 private TaskSnapshotSurface mOuter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700448
Jorim Jaggi02886a82016-12-06 09:10:06 -0800449 public void setOuter(TaskSnapshotSurface outer) {
450 mOuter = outer;
451 }
452
453 @Override
454 public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets,
Andrii Kulian44607962017-03-16 11:06:24 -0700455 Rect stableInsets, Rect outsets, boolean reportDraw,
456 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Adrian Roos5c6b6222017-11-07 17:36:10 +0100457 boolean alwaysConsumeNavBar, int displayId,
458 DisplayCutout.ParcelableWrapper displayCutout) {
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700459 if (mergedConfiguration != null && mOuter != null
460 && mOuter.mOrientationOnCreation
461 != mergedConfiguration.getMergedConfiguration().orientation) {
462
463 // The orientation of the screen is changing. We better remove the snapshot ASAP as
464 // we are going to wait on the new window in any case to unfreeze the screen, and
465 // the starting window is not needed anymore.
466 sHandler.post(mOuter::remove);
467 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800468 if (reportDraw) {
469 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
470 }
471 }
472 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200473
474 /**
475 * Helper class to draw the background of the system bars in regions the task snapshot isn't
476 * filling the window.
477 */
478 static class SystemBarBackgroundPainter {
479
480 private final Rect mContentInsets = new Rect();
481 private final Rect mStableInsets = new Rect();
482 private final Paint mStatusBarPaint = new Paint();
483 private final Paint mNavigationBarPaint = new Paint();
484 private final int mStatusBarColor;
485 private final int mNavigationBarColor;
486 private final int mWindowFlags;
487 private final int mWindowPrivateFlags;
488 private final int mSysUiVis;
489
490 SystemBarBackgroundPainter( int windowFlags, int windowPrivateFlags, int sysUiVis,
491 int statusBarColor, int navigationBarColor) {
492 mWindowFlags = windowFlags;
493 mWindowPrivateFlags = windowPrivateFlags;
494 mSysUiVis = sysUiVis;
495 final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
496 mStatusBarColor = DecorView.calculateStatusBarColor(windowFlags,
497 context.getColor(R.color.system_bar_background_semi_transparent),
498 statusBarColor);
499 mNavigationBarColor = navigationBarColor;
500 mStatusBarPaint.setColor(mStatusBarColor);
501 mNavigationBarPaint.setColor(navigationBarColor);
502 }
503
504 void setInsets(Rect contentInsets, Rect stableInsets) {
505 mContentInsets.set(contentInsets);
506 mStableInsets.set(stableInsets);
507 }
508
509 int getStatusBarColorViewHeight() {
510 final boolean forceStatusBarBackground =
511 (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
512 if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
513 mSysUiVis, mStatusBarColor, mWindowFlags, forceStatusBarBackground)) {
514 return getColorViewTopInset(mStableInsets.top, mContentInsets.top);
515 } else {
516 return 0;
517 }
518 }
519
520 private boolean isNavigationBarColorViewVisible() {
521 return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
522 mSysUiVis, mNavigationBarColor, mWindowFlags, false /* force */);
523 }
524
525 void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
526 drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
527 drawNavigationBarBackground(c);
528 }
529
530 @VisibleForTesting
531 void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
532 int statusBarHeight) {
Winson Chung51f42d22018-02-01 14:59:38 -0800533 if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200534 && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
535 final int rightInset = DecorView.getColorViewRightInset(mStableInsets.right,
536 mContentInsets.right);
537 final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
538 c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
539 }
540 }
541
542 @VisibleForTesting
543 void drawNavigationBarBackground(Canvas c) {
544 final Rect navigationBarRect = new Rect();
545 getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
546 navigationBarRect);
547 final boolean visible = isNavigationBarColorViewVisible();
Winson Chung51f42d22018-02-01 14:59:38 -0800548 if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200549 c.drawRect(navigationBarRect, mNavigationBarPaint);
550 }
551 }
552 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800553}