summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author wilsonshih <wilsonshih@google.com> 2020-09-28 17:43:40 +0800
committer wilsonshih <wilsonshih@google.com> 2020-12-17 11:00:07 +0800
commit285feba16858c65c33f7d18b133b5f3ada9caad1 (patch)
tree683935c57b5908fff1144ba591b913e61ab4c779
parentf2bda9e3e3cde06ca15645e771ac5fd99e8964b6 (diff)
Mirror TaskSnapshotSurface to WMShell(2/N)
- Let WMShell able to draw task snapshot surface. - Create new class StartingWindowInfo to pass needed data from WM to Shell. - Rename TaskSnapshotSurface -> TaskSnapshotWindow in WMShell. - Mirror and modify a new TaskSnapshotWindowTest in WMShell. Bug: 131727939 Test: atest WindowOrganizerTests ActivityRecordTests TaskSnapshotWindowTest StartingSurfaceDrawerTests Test: build and flash, check shell able to show/remove TaskSnapshotWindow Change-Id: I70dec8ce2bf1ed7d876657324e51357690c8b396
-rw-r--r--core/api/test-current.txt11
-rw-r--r--core/java/android/window/ITaskOrganizer.aidl7
-rw-r--r--core/java/android/window/StartingWindowInfo.aidl20
-rw-r--r--core/java/android/window/StartingWindowInfo.java150
-rw-r--r--core/java/android/window/TaskOrganizer.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java11
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java189
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java622
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java27
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java293
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java11
-rw-r--r--services/core/java/com/android/server/wm/SnapshotStartingData.java7
-rw-r--r--services/core/java/com/android/server/wm/SplashScreenStartingData.java4
-rw-r--r--services/core/java/com/android/server/wm/StartingData.java4
-rw-r--r--services/core/java/com/android/server/wm/StartingSurfaceController.java84
-rw-r--r--services/core/java/com/android/server/wm/Task.java31
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java8
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java30
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java17
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java5
21 files changed, 1439 insertions, 113 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f51bb95bd710..5120fb3ee314 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -2457,6 +2457,13 @@ package android.window {
field public static final int FEATURE_WINDOW_TOKENS = 2; // 0x2
}
+ public final class StartingWindowInfo implements android.os.Parcelable {
+ ctor public StartingWindowInfo();
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.window.StartingWindowInfo> CREATOR;
+ }
+
public final class TaskAppearedInfo implements android.os.Parcelable {
ctor public TaskAppearedInfo(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.view.SurfaceControl);
method public int describeContents();
@@ -2468,7 +2475,7 @@ package android.window {
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
- method @BinderThread public void addStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo, @NonNull android.os.IBinder);
+ method @BinderThread public void addStartingWindow(@NonNull android.window.StartingWindowInfo, @NonNull android.os.IBinder);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void createRootTask(int, int, @Nullable android.os.IBinder);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]);
@@ -2479,7 +2486,7 @@ package android.window {
method @BinderThread public void onTaskInfoChanged(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @BinderThread public void onTaskVanished(@NonNull android.app.ActivityManager.RunningTaskInfo);
method @CallSuper @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public java.util.List<android.window.TaskAppearedInfo> registerOrganizer();
- method @BinderThread public void removeStartingWindow(@NonNull android.app.ActivityManager.RunningTaskInfo);
+ method @BinderThread public void removeStartingWindow(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setInterceptBackPressedOnTaskRoot(@NonNull android.window.WindowContainerToken, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void setLaunchRoot(int, @NonNull android.window.WindowContainerToken);
method @CallSuper @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void unregisterOrganizer();
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index b503184f4c51..88b2257a55b1 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -18,6 +18,7 @@ package android.window;
import android.view.SurfaceControl;
import android.app.ActivityManager;
+import android.window.StartingWindowInfo;
import android.window.WindowContainerToken;
/**
@@ -30,15 +31,15 @@ oneway interface ITaskOrganizer {
* application is starting. The client is responsible to add/remove the starting window if it
* has create a starting window for the Task.
*
- * @param taskInfo The information about the Task that's available
+ * @param info The information about the Task that's available
* @param appToken Token of the application being started.
*/
- void addStartingWindow(in ActivityManager.RunningTaskInfo taskInfo, IBinder appToken);
+ void addStartingWindow(in StartingWindowInfo info, IBinder appToken);
/**
* Called when the Task want to remove the starting window.
*/
- void removeStartingWindow(in ActivityManager.RunningTaskInfo taskInfo);
+ void removeStartingWindow(int taskId);
/**
* A callback when the Task is available for the registered organizer. The client is responsible
diff --git a/core/java/android/window/StartingWindowInfo.aidl b/core/java/android/window/StartingWindowInfo.aidl
new file mode 100644
index 000000000000..69b18f05fa8c
--- /dev/null
+++ b/core/java/android/window/StartingWindowInfo.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+/** @hide */
+parcelable StartingWindowInfo; \ No newline at end of file
diff --git a/core/java/android/window/StartingWindowInfo.java b/core/java/android/window/StartingWindowInfo.java
new file mode 100644
index 000000000000..2282cc567936
--- /dev/null
+++ b/core/java/android/window/StartingWindowInfo.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.InsetsState;
+import android.view.WindowManager;
+
+/**
+ * Information you can retrieve about a starting window of a particular task that is currently
+ * start in the system.
+ * @hide
+ */
+@TestApi
+public final class StartingWindowInfo implements Parcelable {
+ /**
+ * The {@link TaskInfo} from this task.
+ * @hide
+ */
+ @NonNull
+ public ActivityManager.RunningTaskInfo taskInfo;
+
+ /**
+ * InsetsState of TopFullscreenOpaqueWindow
+ * @hide
+ */
+ @Nullable
+ public InsetsState topOpaqueWindowInsetsState;
+
+ /**
+ * LayoutParams of TopFullscreenOpaqueWindow
+ * @hide
+ */
+ @Nullable
+ public WindowManager.LayoutParams topOpaqueWindowLayoutParams;
+
+ /**
+ * LayoutParams of MainWindow
+ * @hide
+ */
+ @Nullable
+ public WindowManager.LayoutParams mainWindowLayoutParams;
+
+ /**
+ * @hide
+ */
+ @IntDef(flag = true, prefix = "TYPE_PARAMETER_", value = {
+ TYPE_PARAMETER_NEW_TASK,
+ TYPE_PARAMETER_TASK_SWITCH,
+ TYPE_PARAMETER_PROCESS_RUNNING,
+ TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT,
+ TYPE_PARAMETER_ACTIVITY_CREATED
+ })
+ public @interface StartingTypeParams {}
+
+ /**
+ * The parameters of the starting window...
+ * @hide
+ */
+ public static final int TYPE_PARAMETER_NEW_TASK = 0x00000001;
+ /** @hide */
+ public static final int TYPE_PARAMETER_TASK_SWITCH = 0x00000002;
+ /** @hide */
+ public static final int TYPE_PARAMETER_PROCESS_RUNNING = 0x00000004;
+ /** @hide */
+ public static final int TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT = 0x00000008;
+ /** @hide */
+ public static final int TYPE_PARAMETER_ACTIVITY_CREATED = 0x00000010;
+
+ /**
+ * The parameters which effect the starting window type.
+ * @see android.window.StartingWindowInfo.StartingTypeParams
+ * @hide
+ */
+ public int startingWindowTypeParameter;
+
+ public StartingWindowInfo() {
+
+ }
+
+ private StartingWindowInfo(@NonNull Parcel source) {
+ readFromParcel(source);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeTypedObject(taskInfo, flags);
+ dest.writeInt(startingWindowTypeParameter);
+ dest.writeTypedObject(topOpaqueWindowInsetsState, flags);
+ dest.writeTypedObject(topOpaqueWindowLayoutParams, flags);
+ dest.writeTypedObject(mainWindowLayoutParams, flags);
+ }
+
+ void readFromParcel(@NonNull Parcel source) {
+ taskInfo = source.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
+ startingWindowTypeParameter = source.readInt();
+ topOpaqueWindowInsetsState = source.readTypedObject(InsetsState.CREATOR);
+ topOpaqueWindowLayoutParams = source.readTypedObject(
+ WindowManager.LayoutParams.CREATOR);
+ mainWindowLayoutParams = source.readTypedObject(WindowManager.LayoutParams.CREATOR);
+ }
+
+ @Override
+ public String toString() {
+ return "StartingWindowInfo{taskId=" + taskInfo.taskId
+ + " displayId=" + taskInfo.displayId
+ + " topActivityType=" + taskInfo.topActivityType
+ + " preferredStartingWindowType="
+ + Integer.toHexString(startingWindowTypeParameter)
+ + " insetsState=" + topOpaqueWindowInsetsState
+ + " topWindowLayoutParams=" + topOpaqueWindowLayoutParams
+ + " mainWindowLayoutParams=" + mainWindowLayoutParams;
+ }
+
+ public static final @android.annotation.NonNull Creator<StartingWindowInfo> CREATOR =
+ new Creator<StartingWindowInfo>() {
+ public StartingWindowInfo createFromParcel(@NonNull Parcel source) {
+ return new StartingWindowInfo(source);
+ }
+ public StartingWindowInfo[] newArray(int size) {
+ return new StartingWindowInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/window/TaskOrganizer.java b/core/java/android/window/TaskOrganizer.java
index 12c4b5b7794a..73b2fe1ff4d5 100644
--- a/core/java/android/window/TaskOrganizer.java
+++ b/core/java/android/window/TaskOrganizer.java
@@ -89,19 +89,19 @@ public class TaskOrganizer extends WindowOrganizer {
* application is starting. The client is responsible to add/remove the starting window if it
* has create a starting window for the Task.
*
- * @param taskInfo The information about the Task that's available
+ * @param info The information about the Task that's available
* @param appToken Token of the application being started.
* context to for resources
*/
@BinderThread
- public void addStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo,
+ public void addStartingWindow(@NonNull StartingWindowInfo info,
@NonNull IBinder appToken) {}
/**
* Called when the Task want to remove the starting window.
*/
@BinderThread
- public void removeStartingWindow(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
+ public void removeStartingWindow(int taskId) {}
/**
* Called when a task with the registered windowing mode can be controlled by this task
@@ -221,13 +221,15 @@ public class TaskOrganizer extends WindowOrganizer {
private final ITaskOrganizer mInterface = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
- mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(taskInfo, appToken));
+
+ public void addStartingWindow(StartingWindowInfo windowInfo,
+ IBinder appToken) {
+ mExecutor.execute(() -> TaskOrganizer.this.addStartingWindow(windowInfo, appToken));
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
- mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskInfo));
+ public void removeStartingWindow(int taskId) {
+ mExecutor.execute(() -> TaskOrganizer.this.removeStartingWindow(taskId));
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index 8d1508019cda..c9b38d00c0ae 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -34,6 +34,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.window.ITaskOrganizerController;
+import android.window.StartingWindowInfo;
import android.window.TaskAppearedInfo;
import android.window.TaskOrganizer;
@@ -112,7 +113,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
// TODO(b/131727939) temporarily live here, the starting surface drawer should be controlled
// by a controller, that class should be create while porting
// ActivityRecord#addStartingWindow to WMShell.
- mStartingSurfaceDrawer = new StartingSurfaceDrawer(context);
+ mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
}
@Override
@@ -229,13 +230,13 @@ public class ShellTaskOrganizer extends TaskOrganizer {
}
@Override
- public void addStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) {
- mStartingSurfaceDrawer.addStartingWindow(taskInfo, appToken);
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
+ mStartingSurfaceDrawer.addStartingWindow(info, appToken);
}
@Override
- public void removeStartingWindow(RunningTaskInfo taskInfo) {
- mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+ public void removeStartingWindow(int taskId) {
+ mStartingSurfaceDrawer.removeStartingWindow(taskId);
}
@Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index ee79824ff4a7..e144ca322686 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -16,11 +16,18 @@
package com.android.wm.shell.startingsurface;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.res.Configuration.EMPTY;
import static android.view.Display.DEFAULT_DISPLAY;
-
-import android.app.ActivityManager;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityTaskManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
@@ -30,18 +37,20 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
-import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
+import android.os.RemoteException;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
+import android.window.StartingWindowInfo;
import android.window.TaskOrganizer;
+import android.window.TaskSnapshot;
import com.android.internal.R;
import com.android.internal.policy.PhoneWindow;
+import com.android.wm.shell.common.ShellExecutor;
import java.util.function.Consumer;
@@ -56,22 +65,24 @@ import java.util.function.Consumer;
* @hide
*/
public class StartingSurfaceDrawer {
- private static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
- private static final boolean DEBUG_SPLASH_SCREEN = false;
+ static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
+ static final boolean DEBUG_SPLASH_SCREEN = false;
+ static final boolean DEBUG_TASK_SNAPSHOT = false;
private final Context mContext;
private final DisplayManager mDisplayManager;
+ final ShellExecutor mMainExecutor;
// TODO(b/131727939) remove this when clearing ActivityRecord
private static final int REMOVE_WHEN_TIMEOUT = 2000;
- public StartingSurfaceDrawer(Context context) {
+ public StartingSurfaceDrawer(Context context, ShellExecutor mainExecutor) {
mContext = context;
mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ mMainExecutor = mainExecutor;
}
- private final Handler mHandler = new Handler(Looper.getMainLooper());
- private final SparseArray<TaskScreenView> mTaskScreenViews = new SparseArray<>();
+ private final SparseArray<StartingWindowRecord> mStartingWindowRecords = new SparseArray<>();
/** Obtain proper context for showing splash screen on the provided display. */
private Context getDisplayContext(Context context, int displayId) {
@@ -90,12 +101,111 @@ public class StartingSurfaceDrawer {
return context.createDisplayContext(targetDisplay);
}
+ private static class PreferredStartingTypeHelper {
+ private static final int STARTING_TYPE_NO = 0;
+ private static final int STARTING_TYPE_SPLASH_SCREEN = 1;
+ private static final int STARTING_TYPE_SNAPSHOT = 2;
+
+ TaskSnapshot mSnapshot;
+ int mPreferredType;
+
+ PreferredStartingTypeHelper(StartingWindowInfo taskInfo) {
+ final int parameter = taskInfo.startingWindowTypeParameter;
+ final boolean newTask = (parameter & TYPE_PARAMETER_NEW_TASK) != 0;
+ final boolean taskSwitch = (parameter & TYPE_PARAMETER_TASK_SWITCH) != 0;
+ final boolean processRunning = (parameter & TYPE_PARAMETER_PROCESS_RUNNING) != 0;
+ final boolean allowTaskSnapshot = (parameter & TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT) != 0;
+ final boolean activityCreated = (parameter & TYPE_PARAMETER_ACTIVITY_CREATED) != 0;
+ mPreferredType = preferredStartingWindowType(taskInfo, newTask, taskSwitch,
+ processRunning, allowTaskSnapshot, activityCreated);
+ }
+
+ // reference from ActivityRecord#getStartingWindowType
+ private int preferredStartingWindowType(StartingWindowInfo windowInfo,
+ boolean newTask, boolean taskSwitch, boolean processRunning,
+ boolean allowTaskSnapshot, boolean activityCreated) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "preferredStartingWindowType newTask " + newTask
+ + " taskSwitch " + taskSwitch
+ + " processRunning " + processRunning
+ + " allowTaskSnapshot " + allowTaskSnapshot
+ + " activityCreated " + activityCreated);
+ }
+
+ if (newTask || !processRunning || (taskSwitch && !activityCreated)) {
+ return STARTING_TYPE_SPLASH_SCREEN;
+ } else if (taskSwitch && allowTaskSnapshot) {
+ final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
+ if (isSnapshotCompatible(windowInfo, snapshot)) {
+ return STARTING_TYPE_SNAPSHOT;
+ }
+ if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
+ return STARTING_TYPE_SPLASH_SCREEN;
+ }
+ return STARTING_TYPE_NO;
+ } else {
+ return STARTING_TYPE_NO;
+ }
+ }
+
+ /**
+ * Returns {@code true} if the task snapshot is compatible with this activity (at least the
+ * rotation must be the same).
+ */
+ private boolean isSnapshotCompatible(StartingWindowInfo windowInfo, TaskSnapshot snapshot) {
+ if (snapshot == null) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible no snapshot " + windowInfo.taskInfo.taskId);
+ }
+ return false;
+ }
+
+ final int taskRotation = windowInfo.taskInfo.configuration
+ .windowConfiguration.getRotation();
+ final int snapshotRotation = snapshot.getRotation();
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "isSnapshotCompatible rotation " + taskRotation
+ + " snapshot " + snapshotRotation);
+ }
+ return taskRotation == snapshotRotation;
+ }
+
+ private TaskSnapshot getTaskSnapshot(int taskId) {
+ if (mSnapshot != null) {
+ return mSnapshot;
+ }
+ try {
+ mSnapshot = ActivityTaskManager.getService().getTaskSnapshot(taskId,
+ false/* isLowResolution */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to get snapshot for task: " + taskId + ", from: " + e);
+ return null;
+ }
+ return mSnapshot;
+ }
+ }
+
/**
* Called when a task need a starting window.
*/
- public void addStartingWindow(ActivityManager.RunningTaskInfo taskInfo, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
+ final PreferredStartingTypeHelper helper =
+ new PreferredStartingTypeHelper(windowInfo);
+ final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
+ if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) {
+ addSplashScreenStartingWindow(runningTaskInfo, appToken);
+ } else if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SNAPSHOT) {
+ final TaskSnapshot snapshot = helper.mSnapshot;
+ makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
+ }
+ // If prefer don't show, then don't show!
+ }
+ private void addSplashScreenStartingWindow(RunningTaskInfo taskInfo, IBinder appToken) {
final ActivityInfo activityInfo = taskInfo.topActivityInfo;
+ if (activityInfo == null) {
+ return;
+ }
final int displayId = taskInfo.displayId;
if (activityInfo.packageName == null) {
return;
@@ -250,18 +360,34 @@ public class StartingSurfaceDrawer {
}
/**
+ * Called when a task need a snapshot starting window.
+ */
+ private void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo,
+ IBinder appToken, TaskSnapshot snapshot) {
+ final int taskId = startingWindowInfo.taskInfo.taskId;
+ final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
+ snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
+ mMainExecutor.execute(() -> {
+ mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ final StartingWindowRecord tView =
+ new StartingWindowRecord(null/* decorView */, surface);
+ mStartingWindowRecords.put(taskId, tView);
+ });
+ }
+
+ /**
* Called when the content of a task is ready to show, starting window can be removed.
*/
- public void removeStartingWindow(ActivityManager.RunningTaskInfo taskInfo) {
- if (DEBUG_SPLASH_SCREEN) {
- Slog.d(TAG, "Task start finish, remove starting surface for task " + taskInfo.taskId);
+ public void removeStartingWindow(int taskId) {
+ if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
+ Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
}
- mHandler.post(() -> removeWindowSynced(taskInfo.taskId));
+ mMainExecutor.execute(() -> removeWindowSynced(taskId));
}
protected void postAddWindow(int taskId, IBinder appToken,
View view, WindowManager wm, WindowManager.LayoutParams params) {
- mHandler.post(() -> {
+ mMainExecutor.execute(() -> {
boolean shouldSaveView = true;
try {
wm.addView(view, params);
@@ -286,25 +412,32 @@ public class StartingSurfaceDrawer {
if (shouldSaveView) {
removeWindowSynced(taskId);
- mHandler.postDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
- final TaskScreenView tView = new TaskScreenView(view);
- mTaskScreenViews.put(taskId, tView);
+ mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
+ final StartingWindowRecord tView =
+ new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
+ mStartingWindowRecords.put(taskId, tView);
}
});
}
protected void removeWindowSynced(int taskId) {
- final TaskScreenView preView = mTaskScreenViews.get(taskId);
- if (preView != null) {
- if (preView.mDecorView != null) {
+ final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
+ if (record != null) {
+ if (record.mDecorView != null) {
if (DEBUG_SPLASH_SCREEN) {
Slog.v(TAG, "Removing splash screen window for task: " + taskId);
}
- final WindowManager wm = preView.mDecorView.getContext()
+ final WindowManager wm = record.mDecorView.getContext()
.getSystemService(WindowManager.class);
- wm.removeView(preView.mDecorView);
+ wm.removeView(record.mDecorView);
+ }
+ if (record.mTaskSnapshotWindow != null) {
+ if (DEBUG_TASK_SNAPSHOT) {
+ Slog.v(TAG, "Removing task snapshot window for " + taskId);
+ }
+ record.mTaskSnapshotWindow.remove(mMainExecutor);
}
- mTaskScreenViews.remove(taskId);
+ mStartingWindowRecords.remove(taskId);
}
}
@@ -315,13 +448,15 @@ public class StartingSurfaceDrawer {
}
/**
- * Record the views in a starting window.
+ * Record the view or surface for a starting window.
*/
- private static class TaskScreenView {
+ private static class StartingWindowRecord {
private final View mDecorView;
+ private final TaskSnapshotWindow mTaskSnapshotWindow;
- TaskScreenView(View decorView) {
+ StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
mDecorView = decorView;
+ mTaskSnapshotWindow = taskSnapshotWindow;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
new file mode 100644
index 000000000000..e66d85f55ca9
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -0,0 +1,622 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.graphics.Color.WHITE;
+import static android.graphics.Color.alpha;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+
+import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.getNavigationBarRect;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskDescription;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.MergedConfiguration;
+import android.util.Slog;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+import android.window.ClientWindowFrames;
+import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.DecorView;
+import com.android.internal.view.BaseIWindow;
+import com.android.wm.shell.common.ShellExecutor;
+
+/**
+ * This class represents a starting window that shows a snapshot.
+ *
+ * @hide
+ */
+public class TaskSnapshotWindow {
+
+ private static final long SIZE_MISMATCH_MINIMUM_TIME_MS = 450;
+
+ /**
+ * When creating the starting window, we use the exact same layout flags such that we end up
+ * with a window with the exact same dimensions etc. However, these flags are not used in layout
+ * and might cause other side effects so we exclude them.
+ */
+ static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+ | FLAG_NOT_TOUCHABLE
+ | FLAG_NOT_TOUCH_MODAL
+ | FLAG_ALT_FOCUSABLE_IM
+ | FLAG_NOT_FOCUSABLE
+ | FLAG_HARDWARE_ACCELERATED
+ | FLAG_IGNORE_CHEEK_PRESSES
+ | FLAG_LOCAL_FOCUS_MODE
+ | FLAG_SLIPPERY
+ | FLAG_WATCH_OUTSIDE_TOUCH
+ | FLAG_SPLIT_TOUCH
+ | FLAG_SCALED
+ | FLAG_SECURE;
+
+ private static final String TAG = StartingSurfaceDrawer.TAG;
+ private static final boolean DEBUG = StartingSurfaceDrawer.DEBUG_TASK_SNAPSHOT;
+ private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
+
+ //tmp vars for unused relayout params
+ private static final Point TMP_SURFACE_SIZE = new Point();
+
+ private final Window mWindow;
+ private final Surface mSurface;
+ private final Runnable mClearWindowHandler;
+ private SurfaceControl mSurfaceControl;
+ private SurfaceControl mChildSurfaceControl;
+ private final IWindowSession mSession;
+ private final Rect mTaskBounds;
+ private final Rect mFrame = new Rect();
+ private final Rect mSystemBarInsets = new Rect();
+ private TaskSnapshot mSnapshot;
+ private final RectF mTmpSnapshotSize = new RectF();
+ private final RectF mTmpDstFrame = new RectF();
+ private final CharSequence mTitle;
+ private boolean mHasDrawn;
+ private long mShownTime;
+ private boolean mSizeMismatch;
+ private final Paint mBackgroundPaint = new Paint();
+ private final int mActivityType;
+ private final int mStatusBarColor;
+ private final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
+ private final int mOrientationOnCreation;
+ private final SurfaceControl.Transaction mTransaction;
+ private final Matrix mSnapshotMatrix = new Matrix();
+ private final float[] mTmpFloat9 = new float[9];
+
+ static TaskSnapshotWindow create(StartingWindowInfo info, IBinder appToken,
+ TaskSnapshot snapshot, ShellExecutor mainExecutor, Runnable clearWindowHandler) {
+ final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo;
+ final int taskId = runningTaskInfo.taskId;
+ if (DEBUG) {
+ Slog.d(TAG, "create taskSnapshot surface for task: " + taskId);
+ }
+
+ final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
+ final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams;
+ final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState;
+ if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) {
+ Slog.w(TAG, "unable to create taskSnapshot surface for task: " + taskId);
+ return null;
+ }
+ final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+ final int appearance = attrs.insetsFlags.appearance;
+ final int windowFlags = attrs.flags;
+ final int windowPrivateFlags = attrs.privateFlags;
+
+ layoutParams.packageName = mainWindowParams.packageName;
+ layoutParams.windowAnimations = mainWindowParams.windowAnimations;
+ layoutParams.dimAmount = mainWindowParams.dimAmount;
+ layoutParams.type = TYPE_APPLICATION_STARTING;
+ layoutParams.format = snapshot.getHardwareBuffer().getFormat();
+ layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
+ | FLAG_NOT_FOCUSABLE
+ | FLAG_NOT_TOUCHABLE;
+ // Setting as trusted overlay to let touches pass through. This is safe because this
+ // window is controlled by the system.
+ layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS)
+ | PRIVATE_FLAG_TRUSTED_OVERLAY;
+ layoutParams.token = appToken;
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.insetsFlags.appearance = appearance;
+ layoutParams.insetsFlags.behavior = attrs.insetsFlags.behavior;
+ layoutParams.layoutInDisplayCutoutMode = attrs.layoutInDisplayCutoutMode;
+ layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
+ layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
+ layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
+
+ layoutParams.setTitle(String.format(TITLE_FORMAT, taskId));
+
+ final Point taskSize = snapshot.getTaskSize();
+ final Rect taskBounds = new Rect(0, 0, taskSize.x, taskSize.y);
+ final int orientation = snapshot.getOrientation();
+
+ final int activityType = runningTaskInfo.topActivityType;
+ final int displayId = runningTaskInfo.displayId;
+
+ final IWindowSession session = WindowManagerGlobal.getWindowSession();
+ final SurfaceControl surfaceControl = new SurfaceControl();
+ final ClientWindowFrames tmpFrames = new ClientWindowFrames();
+
+ final InsetsSourceControl[] mTempControls = new InsetsSourceControl[0];
+ final MergedConfiguration tmpMergedConfiguration = new MergedConfiguration();
+
+ final TaskDescription taskDescription;
+ if (runningTaskInfo.taskDescription != null) {
+ taskDescription = runningTaskInfo.taskDescription;
+ } else {
+ taskDescription = new TaskDescription();
+ taskDescription.setBackgroundColor(WHITE);
+ }
+
+ final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
+ surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
+ windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
+ topWindowInsetsState, clearWindowHandler);
+ final Window window = snapshotSurface.mWindow;
+
+ final InsetsState mTmpInsetsState = new InsetsState();
+ final InputChannel tmpInputChannel = new InputChannel();
+ mainExecutor.execute(() -> {
+ try {
+ final int res = session.addToDisplay(window, layoutParams, View.GONE,
+ displayId, mTmpInsetsState, tmpFrames.frame,
+ tmpFrames.displayCutout, tmpInputChannel/* outInputChannel */,
+ mTmpInsetsState, mTempControls);
+ if (res < 0) {
+ Slog.w(TAG, "Failed to add snapshot starting window res=" + res);
+ return;
+ }
+ } catch (RemoteException e) {
+ snapshotSurface.clearWindowSynced();
+ }
+ window.setOuter(snapshotSurface, mainExecutor);
+ try {
+ session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
+ tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
+ mTempControls, TMP_SURFACE_SIZE);
+ } catch (RemoteException e) {
+ snapshotSurface.clearWindowSynced();
+ }
+
+ final Rect systemBarInsets = getSystemBarInsets(tmpFrames.frame, topWindowInsetsState);
+ snapshotSurface.setFrames(tmpFrames.frame, systemBarInsets);
+ snapshotSurface.drawSnapshot();
+ });
+ return snapshotSurface;
+ }
+
+ public TaskSnapshotWindow(SurfaceControl surfaceControl,
+ TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
+ int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
+ int currentOrientation, int activityType, InsetsState topWindowInsetsState,
+ Runnable clearWindowHandler) {
+ mSurface = new Surface();
+ mSession = WindowManagerGlobal.getWindowSession();
+ mWindow = new Window();
+ mWindow.setSession(mSession);
+ mSurfaceControl = surfaceControl;
+ mSnapshot = snapshot;
+ mTitle = title;
+ int backgroundColor = taskDescription.getBackgroundColor();
+ mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
+ mTaskBounds = taskBounds;
+ mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
+ windowPrivateFlags, appearance, taskDescription, 1f, topWindowInsetsState);
+ mStatusBarColor = taskDescription.getStatusBarColor();
+ mOrientationOnCreation = currentOrientation;
+ mActivityType = activityType;
+ mTransaction = new SurfaceControl.Transaction();
+ mClearWindowHandler = clearWindowHandler;
+ }
+
+ /**
+ * Ask system bar background painter to draw status bar background.
+ * @hide
+ */
+ public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+ mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame,
+ mSystemBarBackgroundPainter.getStatusBarColorViewHeight());
+ }
+
+ /**
+ * Ask system bar background painter to draw navigation bar background.
+ * @hide
+ */
+ public void drawNavigationBarBackground(Canvas c) {
+ mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
+ }
+
+ void remove(ShellExecutor mainExecutor) {
+ final long now = SystemClock.uptimeMillis();
+ if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
+ // Show the latest content as soon as possible for unlocking to home.
+ && mActivityType != ACTIVITY_TYPE_HOME) {
+ final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now;
+ mainExecutor.executeDelayed(() -> remove(mainExecutor), delayTime);
+ if (DEBUG) {
+ Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
+ }
+ return;
+ }
+ mainExecutor.execute(() -> {
+ try {
+ if (DEBUG) {
+ Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
+ }
+ mSession.remove(mWindow);
+ } catch (RemoteException e) {
+ // nothing
+ }
+ });
+ }
+
+ /**
+ * Set frame size.
+ * @hide
+ */
+ public void setFrames(Rect frame, Rect systemBarInsets) {
+ mFrame.set(frame);
+ mSystemBarInsets.set(systemBarInsets);
+ final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+ mSizeMismatch = (mFrame.width() != snapshot.getWidth()
+ || mFrame.height() != snapshot.getHeight());
+ mSystemBarBackgroundPainter.setInsets(systemBarInsets);
+ }
+
+ static Rect getSystemBarInsets(Rect frame, InsetsState state) {
+ return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
+ false /* ignoreVisibility */);
+ }
+
+ private void drawSnapshot() {
+ mSurface.copyFrom(mSurfaceControl);
+ if (DEBUG) {
+ Slog.d(TAG, "Drawing snapshot surface sizeMismatch= " + mSizeMismatch);
+ }
+ if (mSizeMismatch) {
+ // The dimensions of the buffer and the window don't match, so attaching the buffer
+ // will fail. Better create a child window with the exact dimensions and fill the parent
+ // window with the background color!
+ drawSizeMismatchSnapshot();
+ } else {
+ drawSizeMatchSnapshot();
+ }
+ mShownTime = SystemClock.uptimeMillis();
+ mHasDrawn = true;
+ reportDrawn();
+
+ // In case window manager leaks us, make sure we don't retain the snapshot.
+ mSnapshot = null;
+ }
+
+ private void drawSizeMatchSnapshot() {
+ mSurface.attachAndQueueBufferWithColorSpace(mSnapshot.getHardwareBuffer(),
+ mSnapshot.getColorSpace());
+ mSurface.release();
+ }
+
+ private void drawSizeMismatchSnapshot() {
+ if (!mSurface.isValid()) {
+ throw new IllegalStateException("mSurface does not hold a valid surface.");
+ }
+ final HardwareBuffer buffer = mSnapshot.getHardwareBuffer();
+ final SurfaceSession session = new SurfaceSession();
+
+ // We consider nearly matched dimensions as there can be rounding errors and the user won't
+ // notice very minute differences from scaling one dimension more than the other
+ final boolean aspectRatioMismatch = Math.abs(
+ ((float) buffer.getWidth() / buffer.getHeight())
+ - ((float) mFrame.width() / mFrame.height())) > 0.01f;
+
+ // Keep a reference to it such that it doesn't get destroyed when finalized.
+ mChildSurfaceControl = new SurfaceControl.Builder(session)
+ .setName(mTitle + " - task-snapshot-surface")
+ .setBufferSize(buffer.getWidth(), buffer.getHeight())
+ .setFormat(buffer.getFormat())
+ .setParent(mSurfaceControl)
+ .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot")
+ .build();
+ Surface surface = new Surface();
+ surface.copyFrom(mChildSurfaceControl);
+
+ final Rect frame;
+ // We can just show the surface here as it will still be hidden as the parent is
+ // still hidden.
+ mTransaction.show(mChildSurfaceControl);
+ if (aspectRatioMismatch) {
+ // Clip off ugly navigation bar.
+ final Rect crop = calculateSnapshotCrop();
+ frame = calculateSnapshotFrame(crop);
+ mTransaction.setWindowCrop(mChildSurfaceControl, crop);
+ mTransaction.setPosition(mChildSurfaceControl, frame.left, frame.top);
+ mTmpSnapshotSize.set(crop);
+ mTmpDstFrame.set(frame);
+ } else {
+ frame = null;
+ mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
+ mTmpDstFrame.set(mFrame);
+ mTmpDstFrame.offsetTo(0, 0);
+ }
+
+ // Scale the mismatch dimensions to fill the task bounds
+ mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
+ mTransaction.setMatrix(mChildSurfaceControl, mSnapshotMatrix, mTmpFloat9);
+
+ mTransaction.apply();
+ surface.attachAndQueueBufferWithColorSpace(buffer, mSnapshot.getColorSpace());
+ surface.release();
+
+ if (aspectRatioMismatch) {
+ final Canvas c = mSurface.lockCanvas(null);
+ drawBackgroundAndBars(c, frame);
+ mSurface.unlockCanvasAndPost(c);
+ mSurface.release();
+ }
+ }
+
+ /**
+ * Calculates the snapshot crop in snapshot coordinate space.
+ *
+ * @return crop rect in snapshot coordinate space.
+ */
+ public Rect calculateSnapshotCrop() {
+ final Rect rect = new Rect();
+ final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+ rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight());
+ final Rect insets = mSnapshot.getContentInsets();
+
+ final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+ final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+ // Let's remove all system decorations except the status bar, but only if the task is at the
+ // very top of the screen.
+ final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
+ rect.inset((int) (insets.left * scaleX),
+ isTop ? 0 : (int) (insets.top * scaleY),
+ (int) (insets.right * scaleX),
+ (int) (insets.bottom * scaleY));
+ return rect;
+ }
+
+ /**
+ * Calculates the snapshot frame in window coordinate space from crop.
+ *
+ * @param crop rect that is in snapshot coordinate space.
+ */
+ public Rect calculateSnapshotFrame(Rect crop) {
+ final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+ final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+ final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+ // Rescale the frame from snapshot to window coordinate space
+ final Rect frame = new Rect(0, 0,
+ (int) (crop.width() / scaleX + 0.5f),
+ (int) (crop.height() / scaleY + 0.5f)
+ );
+
+ // However, we also need to make space for the navigation bar on the left side.
+ frame.offset(mSystemBarInsets.left, 0);
+ return frame;
+ }
+
+ /**
+ * Draw status bar and navigation bar background.
+ * @hide
+ */
+ public void drawBackgroundAndBars(Canvas c, Rect frame) {
+ final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
+ final boolean fillHorizontally = c.getWidth() > frame.right;
+ final boolean fillVertically = c.getHeight() > frame.bottom;
+ if (fillHorizontally) {
+ c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
+ c.getWidth(), fillVertically
+ ? frame.bottom
+ : c.getHeight(),
+ mBackgroundPaint);
+ }
+ if (fillVertically) {
+ c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
+ }
+ mSystemBarBackgroundPainter.drawDecors(c, frame);
+ }
+
+ /**
+ * Clear window from drawer, must be post on main executor.
+ */
+ private void clearWindowSynced() {
+ if (mClearWindowHandler != null) {
+ mClearWindowHandler.run();
+ }
+ }
+
+ private void reportDrawn() {
+ try {
+ mSession.finishDrawing(mWindow, null /* postDrawTransaction */);
+ } catch (RemoteException e) {
+ clearWindowSynced();
+ }
+ }
+
+ static class Window extends BaseIWindow {
+ private TaskSnapshotWindow mOuter;
+ private ShellExecutor mMainExecutor;
+
+ public void setOuter(TaskSnapshotWindow outer, ShellExecutor mainExecutor) {
+ mOuter = outer;
+ mMainExecutor = mainExecutor;
+ }
+
+ @Override
+ public void resized(ClientWindowFrames frames, boolean reportDraw,
+ MergedConfiguration mergedConfiguration, boolean forceLayout,
+ boolean alwaysConsumeSystemBars, int displayId) {
+ if (mOuter != null) {
+ if (mergedConfiguration != null
+ && mOuter.mOrientationOnCreation
+ != mergedConfiguration.getMergedConfiguration().orientation) {
+ // The orientation of the screen is changing. We better remove the snapshot ASAP
+ // as we are going to wait on the new window in any case to unfreeze the screen,
+ // and the starting window is not needed anymore.
+ mMainExecutor.execute(() -> {
+ mOuter.clearWindowSynced();
+ });
+ } else if (reportDraw) {
+ mMainExecutor.execute(() -> {
+ if (mOuter.mHasDrawn) {
+ mOuter.reportDrawn();
+ }
+ });
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper class to draw the background of the system bars in regions the task snapshot isn't
+ * filling the window.
+ */
+ static class SystemBarBackgroundPainter {
+ private final Paint mStatusBarPaint = new Paint();
+ private final Paint mNavigationBarPaint = new Paint();
+ private final int mStatusBarColor;
+ private final int mNavigationBarColor;
+ private final int mWindowFlags;
+ private final int mWindowPrivateFlags;
+ private final float mScale;
+ private final InsetsState mInsetsState;
+ private final Rect mSystemBarInsets = new Rect();
+
+ SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
+ TaskDescription taskDescription, float scale, InsetsState insetsState) {
+ mWindowFlags = windowFlags;
+ mWindowPrivateFlags = windowPrivateFlags;
+ mScale = scale;
+ final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
+ final int semiTransparent = context.getColor(
+ R.color.system_bar_background_semi_transparent);
+ mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
+ semiTransparent, taskDescription.getStatusBarColor(), appearance,
+ APPEARANCE_LIGHT_STATUS_BARS,
+ taskDescription.getEnsureStatusBarContrastWhenTransparent());
+ mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
+ FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
+ taskDescription.getNavigationBarColor(), appearance,
+ APPEARANCE_LIGHT_NAVIGATION_BARS,
+ taskDescription.getEnsureNavigationBarContrastWhenTransparent()
+ && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
+ mStatusBarPaint.setColor(mStatusBarColor);
+ mNavigationBarPaint.setColor(mNavigationBarColor);
+ mInsetsState = insetsState;
+ }
+
+ void setInsets(Rect systemBarInsets) {
+ mSystemBarInsets.set(systemBarInsets);
+ }
+
+ int getStatusBarColorViewHeight() {
+ final boolean forceBarBackground =
+ (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+ if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+ mInsetsState, mStatusBarColor, mWindowFlags, forceBarBackground)) {
+ return (int) (mSystemBarInsets.top * mScale);
+ } else {
+ return 0;
+ }
+ }
+
+ private boolean isNavigationBarColorViewVisible() {
+ final boolean forceBarBackground =
+ (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+ return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+ mInsetsState, mNavigationBarColor, mWindowFlags, forceBarBackground);
+ }
+
+ void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+ drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
+ drawNavigationBarBackground(c);
+ }
+
+ void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
+ int statusBarHeight) {
+ if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
+ && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
+ final int rightInset = (int) (mSystemBarInsets.right * mScale);
+ final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
+ c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
+ }
+ }
+
+ @VisibleForTesting
+ void drawNavigationBarBackground(Canvas c) {
+ final Rect navigationBarRect = new Rect();
+ getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
+ mScale);
+ final boolean visible = isNavigationBarColorViewVisible();
+ if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
+ c.drawRect(navigationBarRect, mNavigationBarPaint);
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index f5628abb100f..07115c2b4d22 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -41,11 +41,14 @@ import android.testing.TestableContext;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowMetrics;
+import android.window.StartingWindowInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.wm.shell.common.HandlerExecutor;
+import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
import org.junit.Before;
@@ -70,8 +73,8 @@ public class StartingSurfaceDrawerTests {
static final class TestStartingSurfaceDrawer extends StartingSurfaceDrawer{
int mAddWindowForTask = 0;
- TestStartingSurfaceDrawer(Context context) {
- super(context);
+ TestStartingSurfaceDrawer(Context context, ShellExecutor executor) {
+ super(context, executor);
}
@Override
@@ -109,36 +112,38 @@ public class StartingSurfaceDrawerTests {
doReturn(metrics).when(mMockWindowManager).getMaximumWindowMetrics();
doNothing().when(mMockWindowManager).addView(any(), any());
- mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context));
+ mStartingSurfaceDrawer = spy(new TestStartingSurfaceDrawer(context,
+ new HandlerExecutor(new Handler(Looper.getMainLooper()))));
}
@Test
public void testAddSplashScreenSurface() {
final int taskId = 1;
final Handler mainLoop = new Handler(Looper.getMainLooper());
- final ActivityManager.RunningTaskInfo taskInfo =
- createTaskInfo(taskId, WINDOWING_MODE_FULLSCREEN);
- mStartingSurfaceDrawer.addStartingWindow(taskInfo, mBinder);
+ final StartingWindowInfo windowInfo =
+ createWindowInfo(taskId, WINDOWING_MODE_FULLSCREEN);
+ mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).postAddWindow(eq(taskId), eq(mBinder), any(), any(), any());
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, taskId);
- mStartingSurfaceDrawer.removeStartingWindow(taskInfo);
+ mStartingSurfaceDrawer.removeStartingWindow(windowInfo.taskInfo.taskId);
waitHandlerIdle(mainLoop);
verify(mStartingSurfaceDrawer).removeWindowSynced(eq(taskId));
assertEquals(mStartingSurfaceDrawer.mAddWindowForTask, 0);
}
- private ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
- ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
+ private StartingWindowInfo createWindowInfo(int taskId, int windowingMode) {
+ StartingWindowInfo windowInfo = new StartingWindowInfo();
final ActivityInfo info = new ActivityInfo();
info.applicationInfo = new ApplicationInfo();
info.packageName = "test";
info.theme = android.R.style.Theme;
+ final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo();
taskInfo.topActivityInfo = info;
taskInfo.taskId = taskId;
- taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
- return taskInfo;
+ windowInfo.taskInfo = taskInfo;
+ return windowInfo;
}
private static void waitHandlerIdle(Handler handler) {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
new file mode 100644
index 000000000000..94af32999734
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package unittest.src.com.android.wm.shell.startingsurface;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+
+import android.app.ActivityManager.TaskDescription;
+import android.content.ComponentName;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.view.InsetsState;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.window.TaskSnapshot;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskSnapshotWindow}.
+ *
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaskSnapshotWindowTest {
+
+ private TaskSnapshotWindow mWindow;
+
+ private void setupSurface(int width, int height) {
+ setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, width, height));
+ }
+
+ private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
+ int windowFlags, Rect taskBounds) {
+ // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
+ // this behavior set the taskSize to be the same as the taskBounds width and height. The
+ // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
+ // taken. We assume there is no aspect ratio mismatch between the screenshot and the
+ // taskBounds
+ assertEquals(width, taskBounds.width());
+ assertEquals(height, taskBounds.height());
+ Point taskSize = new Point(taskBounds.width(), taskBounds.height());
+
+ final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
+ mWindow = new TaskSnapshotWindow(new SurfaceControl(), snapshot, "Test",
+ createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
+ 0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
+ taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(),
+ null /* clearWindow */);
+ }
+
+ private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
+ Rect contentInsets) {
+ final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
+ 1, HardwareBuffer.USAGE_CPU_READ_RARELY);
+ return new TaskSnapshot(
+ System.currentTimeMillis(),
+ new ComponentName("", ""), buffer,
+ ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
+ Surface.ROTATION_0, taskSize, contentInsets, false,
+ true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
+ 0 /* systemUiVisibility */, false /* isTranslucent */);
+ }
+
+ private static TaskDescription createTaskDescription(int background, int statusBar,
+ int navigationBar) {
+ final TaskDescription td = new TaskDescription();
+ td.setBackgroundColor(background);
+ td.setStatusBarColor(statusBar);
+ td.setNavigationBarColor(navigationBar);
+ return td;
+ }
+
+ @Test
+ public void fillEmptyBackground_fillHorizontally() {
+ setupSurface(200, 100);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(200);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
+ verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_fillVertically() {
+ setupSurface(100, 200);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(200);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
+ verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_fillBoth() {
+ setupSurface(200, 200);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(200);
+ when(mockCanvas.getHeight()).thenReturn(200);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+ verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+ verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_dontFill_sameSize() {
+ setupSurface(100, 100);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+ verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void fillEmptyBackground_dontFill_bitmapLarger() {
+ setupSurface(100, 100);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
+ verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop() {
+ setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(0, 0, 100, 90), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_taskNotOnTop() {
+ setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150));
+ assertEquals(new Rect(0, 10, 100, 90), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_navBarLeft() {
+ setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(10, 0, 100, 100), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_navBarRight() {
+ setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(0, 0, 90, 100), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotCrop_waterfall() {
+ setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
+ assertEquals(new Rect(5, 0, 95, 90), mWindow.calculateSnapshotCrop());
+ }
+
+ @Test
+ public void testCalculateSnapshotFrame() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 0, 10);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ assertEquals(new Rect(0, 0, 100, 80),
+ mWindow.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
+ }
+
+ @Test
+ public void testCalculateSnapshotFrame_navBarLeft() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(10, 10, 0, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ assertEquals(new Rect(10, 0, 100, 90),
+ mWindow.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
+ }
+
+ @Test
+ public void testCalculateSnapshotFrame_waterfall() {
+ setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
+ final Rect insets = new Rect(0, 10, 0, 10);
+ mWindow.setFrames(new Rect(5, 0, 95, 100), insets);
+ assertEquals(new Rect(0, 0, 90, 90),
+ mWindow.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
+ }
+
+ @Test
+ public void testDrawStatusBarBackground() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 10, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100));
+ verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+ }
+
+ @Test
+ public void testDrawStatusBarBackground_nullFrame() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 10, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawStatusBarBackground(mockCanvas, null);
+ verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+ }
+
+ @Test
+ public void testDrawStatusBarBackground_nope() {
+ setupSurface(100, 100);
+ final Rect insets = new Rect(0, 10, 10, 0);
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100));
+ verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+ }
+
+ @Test
+ public void testDrawNavigationBarBackground() {
+ final Rect insets = new Rect(0, 10, 0, 10);
+ setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, 100, 100));
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawNavigationBarBackground(mockCanvas);
+ verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
+ }
+
+ @Test
+ public void testDrawNavigationBarBackground_left() {
+ final Rect insets = new Rect(10, 10, 0, 0);
+ setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, 100, 100));
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawNavigationBarBackground(mockCanvas);
+ verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
+ }
+
+ @Test
+ public void testDrawNavigationBarBackground_right() {
+ final Rect insets = new Rect(0, 10, 10, 0);
+ setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+ new Rect(0, 0, 100, 100));
+ mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+ final Canvas mockCanvas = mock(Canvas.class);
+ when(mockCanvas.getWidth()).thenReturn(100);
+ when(mockCanvas.getHeight()).thenReturn(100);
+ mWindow.drawNavigationBarBackground(mockCanvas);
+ verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9efa24914915..3390d6728d3a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1759,6 +1759,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
final TaskSnapshot snapshot =
mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
false /* restoreFromDisk */, false /* isLowResolution */);
+ final int typeParameter = mWmService.mStartingSurfaceController
+ .makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
+ allowTaskSnapshot, activityCreated);
final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
allowTaskSnapshot, activityCreated, snapshot);
@@ -1773,7 +1776,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
return false;
}
}
- return createSnapshot(snapshot);
+ return createSnapshot(snapshot, typeParameter);
}
// If this is a translucent window, then don't show a starting window -- the current
@@ -1833,18 +1836,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData");
mStartingData = new SplashScreenStartingData(mWmService, pkg,
theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
- getMergedOverrideConfiguration());
+ getMergedOverrideConfiguration(), typeParameter);
scheduleAddStartingWindow();
return true;
}
- private boolean createSnapshot(TaskSnapshot snapshot) {
+ private boolean createSnapshot(TaskSnapshot snapshot, int typeParams) {
if (snapshot == null) {
return false;
}
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData");
- mStartingData = new SnapshotStartingData(mWmService, snapshot);
+ mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams);
scheduleAddStartingWindow();
return true;
}
diff --git a/services/core/java/com/android/server/wm/SnapshotStartingData.java b/services/core/java/com/android/server/wm/SnapshotStartingData.java
index 6ad3f15f4a5c..2124ed6fd39f 100644
--- a/services/core/java/com/android/server/wm/SnapshotStartingData.java
+++ b/services/core/java/com/android/server/wm/SnapshotStartingData.java
@@ -28,14 +28,15 @@ class SnapshotStartingData extends StartingData {
private final WindowManagerService mService;
private final TaskSnapshot mSnapshot;
- SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot) {
- super(service);
+ SnapshotStartingData(WindowManagerService service, TaskSnapshot snapshot, int typeParams) {
+ super(service, typeParams);
mService = service;
mSnapshot = snapshot;
}
@Override
StartingSurface createStartingSurface(ActivityRecord activity) {
- return mService.mTaskSnapshotController.createStartingSurface(activity, mSnapshot);
+ return mService.mStartingSurfaceController.createTaskSnapshotSurface(activity,
+ mSnapshot);
}
}
diff --git a/services/core/java/com/android/server/wm/SplashScreenStartingData.java b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
index 50a101d58ce3..185a317271ff 100644
--- a/services/core/java/com/android/server/wm/SplashScreenStartingData.java
+++ b/services/core/java/com/android/server/wm/SplashScreenStartingData.java
@@ -38,8 +38,8 @@ class SplashScreenStartingData extends StartingData {
SplashScreenStartingData(WindowManagerService service, String pkg, int theme,
CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon,
- int logo, int windowFlags, Configuration mergedOverrideConfiguration) {
- super(service);
+ int logo, int windowFlags, Configuration mergedOverrideConfiguration, int typeParams) {
+ super(service, typeParams);
mPkg = pkg;
mTheme = theme;
mCompatInfo = compatInfo;
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index 2e6e777dd0d0..a5bd797cbc86 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -24,9 +24,11 @@ import com.android.server.policy.WindowManagerPolicy.StartingSurface;
public abstract class StartingData {
protected final WindowManagerService mService;
+ protected final int mTypeParams;
- protected StartingData(WindowManagerService service) {
+ protected StartingData(WindowManagerService service, int typeParams) {
mService = service;
+ mTypeParams = typeParams;
}
/**
diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java
index 6d7ddf607ffe..94e14dd0a6b8 100644
--- a/services/core/java/com/android/server/wm/StartingSurfaceController.java
+++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java
@@ -16,9 +16,20 @@
package com.android.server.wm;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
+import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
+
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.os.SystemProperties;
+import android.util.Slog;
+import android.window.TaskSnapshot;
import com.android.server.policy.WindowManagerPolicy.StartingSurface;
@@ -26,7 +37,8 @@ import com.android.server.policy.WindowManagerPolicy.StartingSurface;
* Managing to create and release a starting window surface.
*/
public class StartingSurfaceController {
-
+ private static final String TAG = TAG_WITH_CLASS_NAME
+ ? StartingSurfaceController.class.getSimpleName() : TAG_WM;
/** Set to {@code true} to enable shell starting surface drawer. */
private static final boolean DEBUG_ENABLE_SHELL_DRAWER =
SystemProperties.getBoolean("persist.debug.shell_starting_surface", false);
@@ -49,15 +61,79 @@ public class StartingSurfaceController {
final Task task = activity.getTask();
if (task != null && mService.mAtmService.mTaskOrganizerController.addStartingWindow(task,
activity.token)) {
- return new SplashScreenContainerSurface(task);
+ return new ShellStartingSurface(task);
}
return null;
}
- private final class SplashScreenContainerSurface implements StartingSurface {
+ int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
+ boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated) {
+ int parameter = 0;
+ if (newTask) {
+ parameter |= TYPE_PARAMETER_NEW_TASK;
+ }
+ if (taskSwitch) {
+ parameter |= TYPE_PARAMETER_TASK_SWITCH;
+ }
+ if (processRunning) {
+ parameter |= TYPE_PARAMETER_PROCESS_RUNNING;
+ }
+ if (allowTaskSnapshot) {
+ parameter |= TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT;
+ }
+ if (activityCreated) {
+ parameter |= TYPE_PARAMETER_ACTIVITY_CREATED;
+ }
+ return parameter;
+ }
+
+ StartingSurface createTaskSnapshotSurface(ActivityRecord activity, TaskSnapshot taskSnapshot) {
+ final WindowState topFullscreenOpaqueWindow;
+ final Task task;
+ synchronized (mService.mGlobalLock) {
+ final WindowState mainWindow = activity.findMainWindow();
+ task = activity.getTask();
+ if (task == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
+ + activity);
+ return null;
+ }
+ final ActivityRecord topFullscreenActivity =
+ activity.getTask().getTopFullscreenActivity();
+ if (topFullscreenActivity == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
+ + task);
+ return null;
+ }
+ topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
+ if (mainWindow == null || topFullscreenOpaqueWindow == null) {
+ Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
+ + activity);
+ return null;
+ }
+ if (topFullscreenActivity.getWindowConfiguration().getRotation()
+ != taskSnapshot.getRotation()) {
+ // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
+ // that the activity will be updated to the same rotation as the snapshot. Since
+ // the transition is not started yet, fixed rotation transform needs to be applied
+ // earlier to make the snapshot show in a rotated container.
+ activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
+ topFullscreenActivity, false /* checkOpening */);
+ }
+ }
+ if (!DEBUG_ENABLE_SHELL_DRAWER) {
+ return mService.mTaskSnapshotController
+ .createStartingSurface(activity, taskSnapshot);
+ }
+ mService.mAtmService.mTaskOrganizerController.addStartingWindow(task, activity.token);
+ return new ShellStartingSurface(task);
+ }
+
+
+ private final class ShellStartingSurface implements StartingSurface {
private final Task mTask;
- SplashScreenContainerSurface(Task task) {
+ ShellStartingSurface(Task task) {
mTask = task;
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index abd51eef93aa..85b8400cb3ec 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -156,7 +156,6 @@ import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
-import android.window.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppGlobals;
@@ -207,6 +206,8 @@ import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManager.TransitionOldType;
import android.window.ITaskOrganizer;
+import android.window.StartingWindowInfo;
+import android.window.TaskSnapshot;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -4145,6 +4146,34 @@ class Task extends WindowContainer<WindowContainer> {
return info;
}
+ StartingWindowInfo getStartingWindowInfo() {
+ final StartingWindowInfo info = new StartingWindowInfo();
+ info.taskInfo = getTaskInfo();
+
+ final ActivityRecord topActivity = getTopMostActivity();
+ if (topActivity != null) {
+ info.startingWindowTypeParameter =
+ topActivity.mStartingData != null
+ ? topActivity.mStartingData.mTypeParams
+ : 0;
+ final WindowState mainWindow = topActivity.findMainWindow();
+ if (mainWindow != null) {
+ info.mainWindowLayoutParams = mainWindow.getAttrs();
+ }
+ }
+ final ActivityRecord topFullscreenActivity = getTopFullscreenActivity();
+ if (topFullscreenActivity != null) {
+ final WindowState topFullscreenOpaqueWindow =
+ topFullscreenActivity.getTopFullscreenOpaqueWindow();
+ if (topFullscreenOpaqueWindow != null) {
+ info.topOpaqueWindowInsetsState =
+ topFullscreenOpaqueWindow.getInsetsStateWithVisibilityOverride();
+ info.topOpaqueWindowLayoutParams = topFullscreenOpaqueWindow.getAttrs();
+ }
+ }
+ return info;
+ }
+
boolean isTaskId(int taskId) {
return mTaskId == taskId;
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 9f8c35b067c5..9b966b3dfe85 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -39,6 +39,7 @@ import android.util.Slog;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
+import android.window.StartingWindowInfo;
import android.window.TaskAppearedInfo;
import android.window.WindowContainerToken;
@@ -116,10 +117,10 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void addStartingWindow(Task task, IBinder appToken) {
- final RunningTaskInfo taskInfo = task.getTaskInfo();
+ final StartingWindowInfo info = task.getStartingWindowInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
- mTaskOrganizer.addStartingWindow(taskInfo, appToken);
+ mTaskOrganizer.addStartingWindow(info, appToken);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onTaskStart callback", e);
}
@@ -127,10 +128,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void removeStartingWindow(Task task) {
- final RunningTaskInfo taskInfo = task.getTaskInfo();
mDeferTaskOrgCallbacksConsumer.accept(() -> {
try {
- mTaskOrganizer.removeStartingWindow(taskInfo);
+ mTaskOrganizer.removeStartingWindow(task.mTaskId);
} catch (RemoteException e) {
Slog.e(TAG, "Exception sending onStartTaskFinished callback", e);
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index d5e4dac4a484..8c458a207cc3 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -49,7 +49,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.annotation.Nullable;
import android.app.ActivityManager.TaskDescription;
-import android.window.TaskSnapshot;
import android.app.ActivityThread;
import android.content.Context;
import android.graphics.Canvas;
@@ -78,6 +77,7 @@ import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.window.ClientWindowFrames;
+import android.window.TaskSnapshot;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -100,7 +100,7 @@ class TaskSnapshotSurface implements StartingSurface {
* with a window with the exact same dimensions etc. However, these flags are not used in layout
* and might cause other side effects so we exclude them.
*/
- private static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+ static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
| FLAG_NOT_TOUCHABLE
| FLAG_NOT_TOUCH_MODAL
| FLAG_ALT_FOCUSABLE_IM
@@ -180,34 +180,10 @@ class TaskSnapshotSurface implements StartingSurface {
synchronized (service.mGlobalLock) {
final WindowState mainWindow = activity.findMainWindow();
final Task task = activity.getTask();
- if (task == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity="
- + activity);
- return null;
- }
final ActivityRecord topFullscreenActivity =
activity.getTask().getTopFullscreenActivity();
- if (topFullscreenActivity == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find top fullscreen for task="
- + task);
- return null;
- }
+ // Already check the nullity in StartingSurfaceController#createTaskSnapshotSurface
topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow();
- if (mainWindow == null || topFullscreenOpaqueWindow == null) {
- Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity="
- + activity);
- return null;
- }
- if (topFullscreenActivity.getWindowConfiguration().getRotation()
- != snapshot.getRotation()) {
- // The snapshot should have been checked by ActivityRecord#isSnapshotCompatible
- // that the activity will be updated to the same rotation as the snapshot. Since
- // the transition is not started yet, fixed rotation transform needs to be applied
- // earlier to make the snapshot show in a rotated container.
- activity.mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(
- topFullscreenActivity, false /* checkOpening */);
- }
-
WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
appearance = attrs.insetsFlags.appearance;
windowFlags = attrs.flags;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 2d71d7f837ef..95a1b61bb5a3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -75,7 +75,6 @@ import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
-import android.window.TaskSnapshot;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
import android.app.servertransaction.ActivityConfigurationChangeItem;
@@ -102,6 +101,7 @@ import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.window.TaskSnapshot;
import androidx.test.filters.MediumTest;
@@ -1662,7 +1662,8 @@ public class ActivityRecordTests extends WindowTestsBase {
any() /* requestedVisibility */, any() /* outFrame */,
any() /* outDisplayCutout */, any() /* outInputChannel */,
any() /* outInsetsState */, any() /* outActiveControls */);
- TaskSnapshotSurface.create(mAtm.mWindowManager, activity, snapshot);
+ mAtm.mWindowManager.mStartingSurfaceController
+ .createTaskSnapshotSurface(activity, snapshot);
} catch (RemoteException ignored) {
} finally {
reset(session);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
index 6b9993aa36cc..62e4990c1487 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java
@@ -74,6 +74,7 @@ import android.view.Display;
import android.view.SurfaceControl;
import android.window.ITaskOrganizer;
import android.window.IWindowContainerTransactionCallback;
+import android.window.StartingWindowInfo;
import android.window.TaskAppearedInfo;
import android.window.WindowContainerTransaction;
@@ -538,12 +539,12 @@ public class WindowOrganizerTests extends WindowTestsBase {
public void testTileAddRemoveChild() {
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -603,12 +604,12 @@ public class WindowOrganizerTests extends WindowTestsBase {
final boolean[] called = {false};
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -674,12 +675,12 @@ public class WindowOrganizerTests extends WindowTestsBase {
final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>();
ITaskOrganizer listener = new ITaskOrganizer.Stub() {
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) { }
@@ -818,9 +819,9 @@ public class WindowOrganizerTests extends WindowTestsBase {
RunningTaskInfo mInfo;
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) { }
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) { }
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) { }
+ public void removeStartingWindow(int taskId) { }
@Override
public void onTaskAppeared(RunningTaskInfo info, SurfaceControl leash) {
mInfo = info;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index e13a5952ccac..89b9707e3e12 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -84,6 +84,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.DisplayImePolicy;
import android.window.ITaskOrganizer;
+import android.window.StartingWindowInfo;
import com.android.internal.util.ArrayUtils;
import com.android.server.AttributeCache;
@@ -1090,10 +1091,10 @@ class WindowTestsBase extends SystemServiceTestsBase {
mMoveToSecondaryOnEnter = move;
}
@Override
- public void addStartingWindow(ActivityManager.RunningTaskInfo info, IBinder appToken) {
+ public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
}
@Override
- public void removeStartingWindow(ActivityManager.RunningTaskInfo info) {
+ public void removeStartingWindow(int taskId) {
}
@Override
public void onTaskAppeared(ActivityManager.RunningTaskInfo info, SurfaceControl leash) {