blob: b3750e95fb36b474eff429b7a6af75a95664f243 [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;
Adrian Roos4c864592019-04-10 14:47:57 +020021import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
22import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020023import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
24import 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;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070034import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
35import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020036import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
Jorim Jaggia6aabac2019-03-11 14:23:16 -070037import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
Jorim Jaggi02886a82016-12-06 09:10:06 -080038import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
Vishnu Naire86bd982018-11-28 13:23:17 -080039
Jorim Jaggi30d64f32017-04-07 16:33:17 +020040import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
41import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
42import static com.android.internal.policy.DecorView.getColorViewLeftInset;
43import static com.android.internal.policy.DecorView.getColorViewTopInset;
44import static com.android.internal.policy.DecorView.getNavigationBarRect;
Adrian Roosb125e0b2019-10-02 14:55:14 +020045import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
Jorim Jaggi02886a82016-12-06 09:10:06 -080046import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
47import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
48
Jorim Jaggid635a4a2017-05-03 15:21:26 +020049import android.annotation.Nullable;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010050import android.app.ActivityManager.TaskDescription;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020051import android.app.ActivityManager.TaskSnapshot;
Jorim Jaggid635a4a2017-05-03 15:21:26 +020052import android.app.ActivityThread;
53import android.content.Context;
Jorim Jaggi02886a82016-12-06 09:10:06 -080054import android.graphics.Canvas;
Winson Chung51f42d22018-02-01 14:59:38 -080055import android.graphics.Color;
Jorim Jaggi02886a82016-12-06 09:10:06 -080056import android.graphics.GraphicBuffer;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010057import android.graphics.Paint;
Jorim Jaggi02886a82016-12-06 09:10:06 -080058import android.graphics.Rect;
59import android.os.Handler;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010060import android.os.Looper;
Jorim Jaggi02886a82016-12-06 09:10:06 -080061import android.os.Message;
62import android.os.RemoteException;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020063import android.os.SystemClock;
Andrii Kulian44607962017-03-16 11:06:24 -070064import android.util.MergedConfiguration;
Jorim Jaggi02886a82016-12-06 09:10:06 -080065import android.util.Slog;
Adrian Roos5c6b6222017-11-07 17:36:10 +010066import android.view.DisplayCutout;
Jorim Jaggi02886a82016-12-06 09:10:06 -080067import android.view.IWindowSession;
Chavi Weingarten6ef9cc62019-02-07 16:28:45 +000068import android.view.InsetsState;
Jorim Jaggi02886a82016-12-06 09:10:06 -080069import android.view.Surface;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020070import android.view.SurfaceControl;
71import android.view.SurfaceSession;
Jorim Jaggi02886a82016-12-06 09:10:06 -080072import android.view.View;
73import android.view.ViewGroup.LayoutParams;
74import android.view.WindowManager;
75import android.view.WindowManagerGlobal;
Jorim Jaggi02886a82016-12-06 09:10:06 -080076
Jorim Jaggi30d64f32017-04-07 16:33:17 +020077import com.android.internal.R;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +010078import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi30d64f32017-04-07 16:33:17 +020079import com.android.internal.policy.DecorView;
Jorim Jaggi02886a82016-12-06 09:10:06 -080080import com.android.internal.view.BaseIWindow;
Adrian Roose99bc052017-11-20 17:55:31 +010081import com.android.server.policy.WindowManagerPolicy.StartingSurface;
Adrian Roosb125e0b2019-10-02 14:55:14 +020082import com.android.server.protolog.common.ProtoLog;
Jorim Jaggi02886a82016-12-06 09:10:06 -080083
84/**
85 * This class represents a starting window that shows a snapshot.
86 * <p>
87 * DO NOT HOLD THE WINDOW MANAGER LOCK WHEN CALLING METHODS OF THIS CLASS!
88 */
89class TaskSnapshotSurface implements StartingSurface {
90
Jorim Jaggi30d64f32017-04-07 16:33:17 +020091 private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
92
93 /**
94 * When creating the starting window, we use the exact same layout flags such that we end up
95 * with a window with the exact same dimensions etc. However, these flags are not used in layout
96 * and might cause other side effects so we exclude them.
97 */
98 private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
99 | FLAG_NOT_TOUCHABLE
100 | FLAG_NOT_TOUCH_MODAL
101 | FLAG_ALT_FOCUSABLE_IM
102 | FLAG_NOT_FOCUSABLE
103 | FLAG_HARDWARE_ACCELERATED
104 | FLAG_IGNORE_CHEEK_PRESSES
105 | FLAG_LOCAL_FOCUS_MODE
106 | FLAG_SLIPPERY
107 | FLAG_WATCH_OUTSIDE_TOUCH
108 | FLAG_SPLIT_TOUCH
109 | FLAG_SCALED
110 | FLAG_SECURE;
111
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700112 private static final int PRIVATE_FLAG_INHERITS = PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
Jorim Jaggid2616322017-06-07 12:38:19 -0700113
Jorim Jaggi02886a82016-12-06 09:10:06 -0800114 private static final String TAG = TAG_WITH_CLASS_NAME ? "SnapshotStartingWindow" : TAG_WM;
115 private static final int MSG_REPORT_DRAW = 0;
116 private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
117 private final Window mWindow;
118 private final Surface mSurface;
Robert Carr5fea55b2018-12-10 13:05:52 -0800119 private SurfaceControl mSurfaceControl;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200120 private SurfaceControl mChildSurfaceControl;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800121 private final IWindowSession mSession;
122 private final WindowManagerService mService;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200123 private final Rect mTaskBounds;
124 private final Rect mStableInsets = new Rect();
125 private final Rect mContentInsets = new Rect();
126 private final Rect mFrame = new Rect();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200127 private TaskSnapshot mSnapshot;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200128 private final CharSequence mTitle;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800129 private boolean mHasDrawn;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200130 private long mShownTime;
131 private final Handler mHandler;
132 private boolean mSizeMismatch;
133 private final Paint mBackgroundPaint = new Paint();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200134 private final int mStatusBarColor;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200135 @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700136 private final int mOrientationOnCreation;
chaviw619da692019-06-10 15:39:40 -0700137 private final SurfaceControl.Transaction mTransaction;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800138
Garfield Tane8d84ab2019-10-11 09:49:40 -0700139 static TaskSnapshotSurface create(WindowManagerService service, ActivityRecord activity,
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200140 TaskSnapshot snapshot) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800141
142 final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
143 final Window window = new Window();
144 final IWindowSession session = WindowManagerGlobal.getWindowSession();
145 window.setSession(session);
Robert Carr5fea55b2018-12-10 13:05:52 -0800146 final SurfaceControl surfaceControl = new SurfaceControl();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800147 final Rect tmpRect = new Rect();
Adrian Roos5c6b6222017-11-07 17:36:10 +0100148 final DisplayCutout.ParcelableWrapper tmpCutout = new DisplayCutout.ParcelableWrapper();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800149 final Rect tmpFrame = new Rect();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200150 final Rect taskBounds;
151 final Rect tmpContentInsets = new Rect();
152 final Rect tmpStableInsets = new Rect();
Jorim Jaggif96c90a2018-09-26 16:55:15 +0200153 final InsetsState mTmpInsetsState = new InsetsState();
Andrii Kulian44607962017-03-16 11:06:24 -0700154 final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
Adrian Roos4c864592019-04-10 14:47:57 +0200155 final TaskDescription taskDescription = new TaskDescription();
156 taskDescription.setBackgroundColor(WHITE);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200157 final int sysUiVis;
158 final int windowFlags;
159 final int windowPrivateFlags;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700160 final int currentOrientation;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700161 synchronized (service.mGlobalLock) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700162 final WindowState mainWindow = activity.findMainWindow();
163 final Task task = activity.getTask();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200164 if (task == null) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700165 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
166 + activity);
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200167 return null;
168 }
Garfield Tane8d84ab2019-10-11 09:49:40 -0700169 final ActivityRecord topFullscreenActivity =
170 activity.getTask().getTopFullscreenActivity();
171 if (topFullscreenActivity == null) {
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200172 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
173 + task);
174 return null;
175 }
Garfield Tane8d84ab2019-10-11 09:49:40 -0700176 final WindowState topFullscreenWindow = topFullscreenActivity.getTopFullscreenWindow();
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200177 if (mainWindow == null || topFullscreenWindow == null) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700178 Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
179 + activity);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200180 return null;
181 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200182 sysUiVis = topFullscreenWindow.getSystemUiVisibility();
183 windowFlags = topFullscreenWindow.getAttrs().flags;
184 windowPrivateFlags = topFullscreenWindow.getAttrs().privateFlags;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200185
Jorim Jaggi90b3c472018-04-06 16:02:07 +0200186 layoutParams.packageName = mainWindow.getAttrs().packageName;
187 layoutParams.windowAnimations = mainWindow.getAttrs().windowAnimations;
Winson Chungbe9be7f2017-06-28 10:55:22 -0700188 layoutParams.dimAmount = mainWindow.getAttrs().dimAmount;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800189 layoutParams.type = TYPE_APPLICATION_STARTING;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200190 layoutParams.format = snapshot.getSnapshot().getFormat();
191 layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
Jorim Jaggi02886a82016-12-06 09:10:06 -0800192 | FLAG_NOT_FOCUSABLE
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200193 | FLAG_NOT_TOUCHABLE;
Wale Ogunwale01ad4342017-06-30 07:07:01 -0700194 layoutParams.privateFlags = windowPrivateFlags & PRIVATE_FLAG_INHERITS;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700195 layoutParams.token = activity.token;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800196 layoutParams.width = LayoutParams.MATCH_PARENT;
197 layoutParams.height = LayoutParams.MATCH_PARENT;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200198 layoutParams.systemUiVisibility = sysUiVis;
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200199 layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
Bryce Lee6d410262017-02-28 15:30:17 -0800200
Adrian Roos4c864592019-04-10 14:47:57 +0200201 final TaskDescription td = task.getTaskDescription();
202 if (td != null) {
203 taskDescription.copyFrom(td);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100204 }
Jorim Jaggie6c6ecb2017-07-20 18:09:20 +0200205 taskBounds = new Rect();
206 task.getBounds(taskBounds);
207 currentOrientation = topFullscreenWindow.getConfiguration().orientation;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800208 }
209 try {
210 final int res = session.addToDisplay(window, window.mSeq, layoutParams,
Garfield Tane8d84ab2019-10-11 09:49:40 -0700211 View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrame, tmpRect, tmpRect,
Jorim Jaggif081f062019-10-24 16:24:54 +0200212 tmpCutout, null, mTmpInsetsState);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800213 if (res < 0) {
214 Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
215 return null;
216 }
217 } catch (RemoteException e) {
218 // Local call.
219 }
220 final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window,
Adrian Roos4c864592019-04-10 14:47:57 +0200221 surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis,
222 windowFlags, windowPrivateFlags, taskBounds,
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700223 currentOrientation);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800224 window.setOuter(snapshotSurface);
225 try {
chaviwbe43ac82018-04-04 15:14:49 -0700226 session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1,
Jorim Jaggif081f062019-10-24 16:24:54 +0200227 tmpFrame, tmpContentInsets, tmpRect, tmpStableInsets, tmpRect,
Robert Carr5fea55b2018-12-10 13:05:52 -0800228 tmpCutout, tmpMergedConfiguration, surfaceControl, mTmpInsetsState);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800229 } catch (RemoteException e) {
230 // Local call.
231 }
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200232 snapshotSurface.setFrames(tmpFrame, tmpContentInsets, tmpStableInsets);
233 snapshotSurface.drawSnapshot();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800234 return snapshotSurface;
235 }
236
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100237 @VisibleForTesting
Robert Carr5fea55b2018-12-10 13:05:52 -0800238 TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl,
Adrian Roos4c864592019-04-10 14:47:57 +0200239 TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
240 int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds,
241 int currentOrientation) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800242 mService = service;
Vishnu Nair33197392019-08-30 10:29:37 -0700243 mSurface = service.mSurfaceFactory.get();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200244 mHandler = new Handler(mService.mH.getLooper());
Jorim Jaggi02886a82016-12-06 09:10:06 -0800245 mSession = WindowManagerGlobal.getWindowSession();
246 mWindow = window;
Robert Carr5fea55b2018-12-10 13:05:52 -0800247 mSurfaceControl = surfaceControl;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200248 mSnapshot = snapshot;
249 mTitle = title;
Adrian Roos4c864592019-04-10 14:47:57 +0200250 int backgroundColor = taskDescription.getBackgroundColor();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200251 mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
252 mTaskBounds = taskBounds;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200253 mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
Winson Chungffde2ea2019-06-17 17:19:13 -0700254 windowPrivateFlags, sysUiVis, taskDescription, 1f);
Adrian Roos4c864592019-04-10 14:47:57 +0200255 mStatusBarColor = taskDescription.getStatusBarColor();
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700256 mOrientationOnCreation = currentOrientation;
chaviw619da692019-06-10 15:39:40 -0700257 mTransaction = mService.mTransactionFactory.get();
Jorim Jaggi02886a82016-12-06 09:10:06 -0800258 }
259
260 @Override
261 public void remove() {
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700262 synchronized (mService.mGlobalLock) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200263 final long now = SystemClock.uptimeMillis();
264 if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) {
265 mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200266 ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
267 "Defer removing snapshot surface in %dms", (now - mShownTime));
268
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200269 return;
270 }
271 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800272 try {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200273 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing snapshot surface");
Jorim Jaggi02886a82016-12-06 09:10:06 -0800274 mSession.remove(mWindow);
275 } catch (RemoteException e) {
276 // Local call.
277 }
278 }
279
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200280 @VisibleForTesting
281 void setFrames(Rect frame, Rect contentInsets, Rect stableInsets) {
282 mFrame.set(frame);
283 mContentInsets.set(contentInsets);
284 mStableInsets.set(stableInsets);
285 mSizeMismatch = (mFrame.width() != mSnapshot.getSnapshot().getWidth()
286 || mFrame.height() != mSnapshot.getSnapshot().getHeight());
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200287 mSystemBarBackgroundPainter.setInsets(contentInsets, stableInsets);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200288 }
289
290 private void drawSnapshot() {
Robert Carr5fea55b2018-12-10 13:05:52 -0800291 mSurface.copyFrom(mSurfaceControl);
292
Adrian Roosb125e0b2019-10-02 14:55:14 +0200293 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Drawing snapshot surface sizeMismatch=%b",
294 mSizeMismatch);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200295 if (mSizeMismatch) {
296 // The dimensions of the buffer and the window don't match, so attaching the buffer
297 // will fail. Better create a child window with the exact dimensions and fill the parent
298 // window with the background color!
Peiyong Linccc06b62019-06-25 17:31:09 -0700299 drawSizeMismatchSnapshot();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200300 } else {
Peiyong Linccc06b62019-06-25 17:31:09 -0700301 drawSizeMatchSnapshot();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200302 }
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700303 synchronized (mService.mGlobalLock) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200304 mShownTime = SystemClock.uptimeMillis();
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100305 mHasDrawn = true;
Jorim Jaggi39367cf2017-03-13 16:41:13 +0100306 }
Jorim Jaggidc9385a2017-05-13 02:00:31 +0200307 reportDrawn();
Jorim Jaggi4448e1e2017-05-16 22:26:02 +0200308
309 // In case window manager leaks us, make sure we don't retain the snapshot.
310 mSnapshot = null;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200311 }
312
Peiyong Linccc06b62019-06-25 17:31:09 -0700313 private void drawSizeMatchSnapshot() {
314 mSurface.attachAndQueueBufferWithColorSpace(mSnapshot.getSnapshot(),
315 mSnapshot.getColorSpace());
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200316 mSurface.release();
317 }
318
Peiyong Linccc06b62019-06-25 17:31:09 -0700319 private void drawSizeMismatchSnapshot() {
Shibin George9696bd32018-02-26 20:29:44 +0530320 if (!mSurface.isValid()) {
321 throw new IllegalStateException("mSurface does not hold a valid surface.");
322 }
Peiyong Linccc06b62019-06-25 17:31:09 -0700323 final GraphicBuffer buffer = mSnapshot.getSnapshot();
Robert Carr5fea55b2018-12-10 13:05:52 -0800324 final SurfaceSession session = new SurfaceSession();
Winson Chung357deda2019-06-23 13:35:41 -0700325 // We consider nearly matched dimensions as there can be rounding errors and the user won't
326 // notice very minute differences from scaling one dimension more than the other
327 final boolean aspectRatioMismatch = Math.abs(
328 ((float) buffer.getWidth() / buffer.getHeight())
329 - ((float) mFrame.width() / mFrame.height())) > 0.01f;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200330
331 // Keep a reference to it such that it doesn't get destroyed when finalized.
Vishnu Nair33197392019-08-30 10:29:37 -0700332 mChildSurfaceControl = mService.mSurfaceControlFactory.apply(session)
Robert Carre625fcf2017-09-01 12:36:28 -0700333 .setName(mTitle + " - task-snapshot-surface")
Vishnu Naire86bd982018-11-28 13:23:17 -0800334 .setBufferSize(buffer.getWidth(), buffer.getHeight())
Robert Carre625fcf2017-09-01 12:36:28 -0700335 .setFormat(buffer.getFormat())
Robert Carr5fea55b2018-12-10 13:05:52 -0800336 .setParent(mSurfaceControl)
Robert Carre625fcf2017-09-01 12:36:28 -0700337 .build();
Vishnu Nair33197392019-08-30 10:29:37 -0700338 Surface surface = mService.mSurfaceFactory.get();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200339 surface.copyFrom(mChildSurfaceControl);
340
Winson Chung357deda2019-06-23 13:35:41 -0700341 final Rect frame;
chaviw619da692019-06-10 15:39:40 -0700342 // We can just show the surface here as it will still be hidden as the parent is
343 // still hidden.
344 mTransaction.show(mChildSurfaceControl);
345 if (aspectRatioMismatch) {
346 // Clip off ugly navigation bar.
347 final Rect crop = calculateSnapshotCrop();
348 frame = calculateSnapshotFrame(crop);
349 mTransaction.setWindowCrop(mChildSurfaceControl, crop);
350 mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top);
351 } else {
352 frame = null;
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200353 }
chaviw619da692019-06-10 15:39:40 -0700354
355 // Scale the mismatch dimensions to fill the task bounds
356 final float scale = 1 / mSnapshot.getScale();
357 mTransaction.setMatrix(mChildSurfaceControl, scale, 0, 0, scale);
358 mTransaction.apply();
Peiyong Linccc06b62019-06-25 17:31:09 -0700359 surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200360 surface.release();
361
Winson Chung357deda2019-06-23 13:35:41 -0700362 if (aspectRatioMismatch) {
363 final Canvas c = mSurface.lockCanvas(null);
364 drawBackgroundAndBars(c, frame);
365 mSurface.unlockCanvasAndPost(c);
366 mSurface.release();
367 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800368 }
369
Matthew Ngcb7ac672017-07-21 17:27:42 -0700370 /**
371 * Calculates the snapshot crop in snapshot coordinate space.
372 *
373 * @return crop rect in snapshot coordinate space.
374 */
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100375 @VisibleForTesting
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200376 Rect calculateSnapshotCrop() {
377 final Rect rect = new Rect();
378 rect.set(0, 0, mSnapshot.getSnapshot().getWidth(), mSnapshot.getSnapshot().getHeight());
379 final Rect insets = mSnapshot.getContentInsets();
380
381 // Let's remove all system decorations except the status bar, but only if the task is at the
382 // very top of the screen.
Adrian Roos98a146d2017-11-29 16:39:44 +0100383 final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
Matthew Ngcb7ac672017-07-21 17:27:42 -0700384 rect.inset((int) (insets.left * mSnapshot.getScale()),
Adrian Roos98a146d2017-11-29 16:39:44 +0100385 isTop ? 0 : (int) (insets.top * mSnapshot.getScale()),
Matthew Ngcb7ac672017-07-21 17:27:42 -0700386 (int) (insets.right * mSnapshot.getScale()),
387 (int) (insets.bottom * mSnapshot.getScale()));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200388 return rect;
389 }
390
Matthew Ngcb7ac672017-07-21 17:27:42 -0700391 /**
392 * Calculates the snapshot frame in window coordinate space from crop.
393 *
394 * @param crop rect that is in snapshot coordinate space.
395 */
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200396 @VisibleForTesting
397 Rect calculateSnapshotFrame(Rect crop) {
398 final Rect frame = new Rect(crop);
Matthew Ngcb7ac672017-07-21 17:27:42 -0700399 final float scale = mSnapshot.getScale();
400
401 // Rescale the frame from snapshot to window coordinate space
402 frame.scale(1 / scale);
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200403
404 // By default, offset it to to top/left corner
Matthew Ngcb7ac672017-07-21 17:27:42 -0700405 frame.offsetTo((int) (-crop.left / scale), (int) (-crop.top / scale));
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200406
407 // However, we also need to make space for the navigation bar on the left side.
408 final int colorViewLeftInset = getColorViewLeftInset(mStableInsets.left,
409 mContentInsets.left);
410 frame.offset(colorViewLeftInset, 0);
411 return frame;
412 }
413
414 @VisibleForTesting
415 void drawBackgroundAndBars(Canvas c, Rect frame) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200416 final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200417 final boolean fillHorizontally = c.getWidth() > frame.right;
418 final boolean fillVertically = c.getHeight() > frame.bottom;
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100419 if (fillHorizontally) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200420 c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
421 c.getWidth(), fillVertically
422 ? frame.bottom
423 : c.getHeight(),
424 mBackgroundPaint);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100425 }
426 if (fillVertically) {
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200427 c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
428 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200429 mSystemBarBackgroundPainter.drawDecors(c, frame);
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100430 }
431
Jorim Jaggi02886a82016-12-06 09:10:06 -0800432 private void reportDrawn() {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800433 try {
Vishnu Nairf7645aa2019-06-18 11:14:01 -0700434 mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
Jorim Jaggi02886a82016-12-06 09:10:06 -0800435 } catch (RemoteException e) {
436 // Local call.
437 }
438 }
439
Jorim Jaggi829b9cd2017-01-23 16:20:53 +0100440 private static Handler sHandler = new Handler(Looper.getMainLooper()) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800441
442 @Override
443 public void handleMessage(Message msg) {
444 switch (msg.what) {
445 case MSG_REPORT_DRAW:
446 final boolean hasDrawn;
447 final TaskSnapshotSurface surface = (TaskSnapshotSurface) msg.obj;
Wale Ogunwaledb485de2018-10-29 09:47:07 -0700448 synchronized (surface.mService.mGlobalLock) {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800449 hasDrawn = surface.mHasDrawn;
Jorim Jaggi02886a82016-12-06 09:10:06 -0800450 }
451 if (hasDrawn) {
452 surface.reportDrawn();
453 }
454 break;
455 }
456 }
457 };
458
Jorim Jaggi30d64f32017-04-07 16:33:17 +0200459 @VisibleForTesting
460 static class Window extends BaseIWindow {
Jorim Jaggi02886a82016-12-06 09:10:06 -0800461
462 private TaskSnapshotSurface mOuter;
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700463
Jorim Jaggi02886a82016-12-06 09:10:06 -0800464 public void setOuter(TaskSnapshotSurface outer) {
465 mOuter = outer;
466 }
467
468 @Override
Jorim Jaggif081f062019-10-24 16:24:54 +0200469 public void resized(Rect frame, Rect contentInsets, Rect visibleInsets,
470 Rect stableInsets, boolean reportDraw,
Andrii Kulian44607962017-03-16 11:06:24 -0700471 MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
Brad Stenninge0573692019-03-11 13:52:46 -0700472 boolean alwaysConsumeSystemBars, int displayId,
Adrian Roos5c6b6222017-11-07 17:36:10 +0100473 DisplayCutout.ParcelableWrapper displayCutout) {
Jorim Jaggi38d44ec2017-06-14 16:04:59 -0700474 if (mergedConfiguration != null && mOuter != null
475 && mOuter.mOrientationOnCreation
476 != mergedConfiguration.getMergedConfiguration().orientation) {
477
478 // The orientation of the screen is changing. We better remove the snapshot ASAP as
479 // we are going to wait on the new window in any case to unfreeze the screen, and
480 // the starting window is not needed anymore.
481 sHandler.post(mOuter::remove);
482 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800483 if (reportDraw) {
484 sHandler.obtainMessage(MSG_REPORT_DRAW, mOuter).sendToTarget();
485 }
486 }
487 }
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200488
489 /**
490 * Helper class to draw the background of the system bars in regions the task snapshot isn't
491 * filling the window.
492 */
493 static class SystemBarBackgroundPainter {
494
495 private final Rect mContentInsets = new Rect();
496 private final Rect mStableInsets = new Rect();
497 private final Paint mStatusBarPaint = new Paint();
498 private final Paint mNavigationBarPaint = new Paint();
499 private final int mStatusBarColor;
500 private final int mNavigationBarColor;
501 private final int mWindowFlags;
502 private final int mWindowPrivateFlags;
503 private final int mSysUiVis;
Winson Chungffde2ea2019-06-17 17:19:13 -0700504 private final float mScale;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200505
Winson Chungffde2ea2019-06-17 17:19:13 -0700506 SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int sysUiVis,
507 TaskDescription taskDescription, float scale) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200508 mWindowFlags = windowFlags;
509 mWindowPrivateFlags = windowPrivateFlags;
510 mSysUiVis = sysUiVis;
Winson Chungffde2ea2019-06-17 17:19:13 -0700511 mScale = scale;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200512 final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700513 final int semiTransparent = context.getColor(
514 R.color.system_bar_background_semi_transparent);
515 mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
Adrian Roos4c864592019-04-10 14:47:57 +0200516 semiTransparent, taskDescription.getStatusBarColor(), sysUiVis,
517 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR,
518 taskDescription.getEnsureStatusBarContrastWhenTransparent());
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700519 mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
Adrian Roos4c864592019-04-10 14:47:57 +0200520 FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
521 taskDescription.getNavigationBarColor(), sysUiVis,
522 SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
523 taskDescription.getEnsureNavigationBarContrastWhenTransparent()
524 && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200525 mStatusBarPaint.setColor(mStatusBarColor);
Adrian Roos4c864592019-04-10 14:47:57 +0200526 mNavigationBarPaint.setColor(mNavigationBarColor);
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200527 }
528
529 void setInsets(Rect contentInsets, Rect stableInsets) {
530 mContentInsets.set(contentInsets);
531 mStableInsets.set(stableInsets);
532 }
533
534 int getStatusBarColorViewHeight() {
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700535 final boolean forceBarBackground =
536 (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200537 if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700538 mSysUiVis, mStatusBarColor, mWindowFlags, forceBarBackground)) {
Winson Chungffde2ea2019-06-17 17:19:13 -0700539 return (int) (getColorViewTopInset(mStableInsets.top, mContentInsets.top) * mScale);
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200540 } else {
541 return 0;
542 }
543 }
544
545 private boolean isNavigationBarColorViewVisible() {
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700546 final boolean forceBarBackground =
547 (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200548 return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
Jorim Jaggia6aabac2019-03-11 14:23:16 -0700549 mSysUiVis, mNavigationBarColor, mWindowFlags, forceBarBackground);
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200550 }
551
552 void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
553 drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
554 drawNavigationBarBackground(c);
555 }
556
557 @VisibleForTesting
558 void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
559 int statusBarHeight) {
Winson Chung51f42d22018-02-01 14:59:38 -0800560 if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200561 && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
Winson Chungffde2ea2019-06-17 17:19:13 -0700562 final int rightInset = (int) (DecorView.getColorViewRightInset(mStableInsets.right,
563 mContentInsets.right) * mScale);
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200564 final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
565 c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
566 }
567 }
568
569 @VisibleForTesting
570 void drawNavigationBarBackground(Canvas c) {
571 final Rect navigationBarRect = new Rect();
572 getNavigationBarRect(c.getWidth(), c.getHeight(), mStableInsets, mContentInsets,
Winson Chungffde2ea2019-06-17 17:19:13 -0700573 navigationBarRect, mScale);
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200574 final boolean visible = isNavigationBarColorViewVisible();
Winson Chung51f42d22018-02-01 14:59:38 -0800575 if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
Jorim Jaggid635a4a2017-05-03 15:21:26 +0200576 c.drawRect(navigationBarRect, mNavigationBarPaint);
577 }
578 }
579 }
Jorim Jaggi02886a82016-12-06 09:10:06 -0800580}