Extract StartingSurface interface on WMShellBaseModule(7/N)
Decouple the dependency for the rest CLs. Bug: 73289295 Bug: 131311659 Test: atest WindowOrganizerTests StartingSurfaceDrawerTests SplashscreenTests Change-Id: Ifd323714184fad285b4d65f8c86c9b8feafc2374
This commit is contained in:
@@ -34,6 +34,31 @@ import android.view.WindowManager;
|
||||
*/
|
||||
@TestApi
|
||||
public final class StartingWindowInfo implements Parcelable {
|
||||
/**
|
||||
* Prefer nothing or not care the type of starting window.
|
||||
* @hide
|
||||
*/
|
||||
public static final int STARTING_WINDOW_TYPE_NONE = 0;
|
||||
/**
|
||||
* Prefer splash screen starting window.
|
||||
* @hide
|
||||
*/
|
||||
public static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 1;
|
||||
/**
|
||||
* Prefer snapshot starting window.
|
||||
* @hide
|
||||
*/
|
||||
public static final int STARTING_WINDOW_TYPE_SNAPSHOT = 2;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@IntDef(flag = true, prefix = "STARTING_WINDOW_TYPE_", value = {
|
||||
STARTING_WINDOW_TYPE_NONE,
|
||||
STARTING_WINDOW_TYPE_SPLASH_SCREEN,
|
||||
STARTING_WINDOW_TYPE_SNAPSHOT
|
||||
})
|
||||
public @interface StartingWindowType {}
|
||||
|
||||
/**
|
||||
* The {@link TaskInfo} from this task.
|
||||
* @hide
|
||||
|
||||
@@ -25,6 +25,7 @@ import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -44,6 +45,7 @@ public class ShellInitImpl {
|
||||
private final FullscreenTaskListener mFullscreenTaskListener;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final Transitions mTransitions;
|
||||
private final Optional<StartingSurface> mStartingSurfaceOptional;
|
||||
|
||||
private final InitImpl mImpl = new InitImpl();
|
||||
|
||||
@@ -53,6 +55,7 @@ public class ShellInitImpl {
|
||||
Optional<LegacySplitScreenController> legacySplitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<AppPairsController> appPairsOptional,
|
||||
Optional<StartingSurface> startingSurfaceOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Transitions transitions,
|
||||
ShellExecutor mainExecutor) {
|
||||
@@ -62,6 +65,7 @@ public class ShellInitImpl {
|
||||
legacySplitScreenOptional,
|
||||
splitScreenOptional,
|
||||
appPairsOptional,
|
||||
startingSurfaceOptional,
|
||||
fullscreenTaskListener,
|
||||
transitions,
|
||||
mainExecutor).mImpl;
|
||||
@@ -73,6 +77,7 @@ public class ShellInitImpl {
|
||||
Optional<LegacySplitScreenController> legacySplitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<AppPairsController> appPairsOptional,
|
||||
Optional<StartingSurface> startingSurfaceOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Transitions transitions,
|
||||
ShellExecutor mainExecutor) {
|
||||
@@ -85,6 +90,7 @@ public class ShellInitImpl {
|
||||
mFullscreenTaskListener = fullscreenTaskListener;
|
||||
mTransitions = transitions;
|
||||
mMainExecutor = mainExecutor;
|
||||
mStartingSurfaceOptional = startingSurfaceOptional;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
@@ -93,6 +99,7 @@ public class ShellInitImpl {
|
||||
|
||||
mShellTaskOrganizer.addListenerForType(
|
||||
mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
|
||||
mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
|
||||
// Register the shell organizer
|
||||
mShellTaskOrganizer.registerOrganizer();
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
|
||||
import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
|
||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -110,7 +110,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
|
||||
private final ArrayMap<IBinder, TaskListener> mLaunchCookieToListener = new ArrayMap<>();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final StartingSurfaceDrawer mStartingSurfaceDrawer;
|
||||
private StartingSurface mStartingSurface;
|
||||
|
||||
/**
|
||||
* In charge of showing size compat UI. Can be {@code null} if device doesn't support size
|
||||
@@ -120,23 +120,19 @@ public class ShellTaskOrganizer extends TaskOrganizer {
|
||||
private final SizeCompatUIController mSizeCompatUI;
|
||||
|
||||
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context) {
|
||||
this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */,
|
||||
new StartingSurfaceDrawer(context, mainExecutor));
|
||||
this(null /* taskOrganizerController */, mainExecutor, context, null /* sizeCompatUI */);
|
||||
}
|
||||
|
||||
public ShellTaskOrganizer(ShellExecutor mainExecutor, Context context, @Nullable
|
||||
SizeCompatUIController sizeCompatUI) {
|
||||
this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI,
|
||||
new StartingSurfaceDrawer(context, mainExecutor));
|
||||
this(null /* taskOrganizerController */, mainExecutor, context, sizeCompatUI);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
ShellTaskOrganizer(ITaskOrganizerController taskOrganizerController, ShellExecutor mainExecutor,
|
||||
Context context, @Nullable SizeCompatUIController sizeCompatUI,
|
||||
StartingSurfaceDrawer startingSurfaceDrawer) {
|
||||
Context context, @Nullable SizeCompatUIController sizeCompatUI) {
|
||||
super(taskOrganizerController, mainExecutor);
|
||||
mSizeCompatUI = sizeCompatUI;
|
||||
mStartingSurfaceDrawer = startingSurfaceDrawer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,6 +158,15 @@ public class ShellTaskOrganizer extends TaskOrganizer {
|
||||
super.createRootTask(displayId, windowingMode, cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void initStartingSurface(StartingSurface startingSurface) {
|
||||
synchronized (mLock) {
|
||||
mStartingSurface = startingSurface;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener for a specific task id.
|
||||
*/
|
||||
@@ -254,17 +259,23 @@ public class ShellTaskOrganizer extends TaskOrganizer {
|
||||
|
||||
@Override
|
||||
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
|
||||
mStartingSurfaceDrawer.addStartingWindow(info, appToken);
|
||||
if (mStartingSurface != null) {
|
||||
mStartingSurface.addStartingWindow(info, appToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeStartingWindow(int taskId) {
|
||||
mStartingSurfaceDrawer.removeStartingWindow(taskId);
|
||||
if (mStartingSurface != null) {
|
||||
mStartingSurface.removeStartingWindow(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copySplashScreenView(int taskId) {
|
||||
mStartingSurfaceDrawer.copySplashScreenView(taskId);
|
||||
if (mStartingSurface != null) {
|
||||
mStartingSurface.copySplashScreenView(taskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 android.os.IBinder;
|
||||
import android.window.StartingWindowInfo;
|
||||
|
||||
/**
|
||||
* Interface to engage starting window feature.
|
||||
*/
|
||||
public interface StartingSurface {
|
||||
/**
|
||||
* Called when a task need a starting window.
|
||||
*/
|
||||
void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken);
|
||||
/**
|
||||
* Called when the content of a task is ready to show, starting window can be removed.
|
||||
*/
|
||||
void removeStartingWindow(int taskId);
|
||||
/**
|
||||
* Called when the Task wants to copy the splash screen.
|
||||
* @param taskId
|
||||
*/
|
||||
void copySplashScreenView(int taskId);
|
||||
}
|
||||
@@ -16,15 +16,9 @@
|
||||
|
||||
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 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;
|
||||
@@ -37,7 +31,6 @@ import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Display;
|
||||
@@ -46,7 +39,6 @@ import android.view.WindowManager;
|
||||
import android.window.SplashScreenView;
|
||||
import android.window.SplashScreenView.SplashScreenViewParcelable;
|
||||
import android.window.StartingWindowInfo;
|
||||
import android.window.TaskOrganizer;
|
||||
import android.window.TaskSnapshot;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -56,19 +48,13 @@ import com.android.wm.shell.common.ShellExecutor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Implementation to draw the starting window to an application, and remove the starting window
|
||||
* until the application displays its own window.
|
||||
*
|
||||
* When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
|
||||
* starting window and attached to the Task, then when the Task want to remove the starting window,
|
||||
* the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
|
||||
* class to remove the starting window of the Task.
|
||||
* A class which able to draw splash screen or snapshot as the starting window for a task.
|
||||
* @hide
|
||||
*/
|
||||
public class StartingSurfaceDrawer {
|
||||
static final String TAG = StartingSurfaceDrawer.class.getSimpleName();
|
||||
static final boolean DEBUG_SPLASH_SCREEN = false;
|
||||
static final boolean DEBUG_TASK_SNAPSHOT = false;
|
||||
static final boolean DEBUG_SPLASH_SCREEN = StartingWindowController.DEBUG_SPLASH_SCREEN;
|
||||
static final boolean DEBUG_TASK_SNAPSHOT = StartingWindowController.DEBUG_TASK_SNAPSHOT;
|
||||
|
||||
private final Context mContext;
|
||||
private final DisplayManager mDisplayManager;
|
||||
@@ -107,106 +93,10 @@ 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.
|
||||
* Called when a task need a splash screen starting window.
|
||||
*/
|
||||
public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
|
||||
final PreferredStartingTypeHelper helper =
|
||||
new PreferredStartingTypeHelper(windowInfo);
|
||||
if (helper.mPreferredType == PreferredStartingTypeHelper.STARTING_TYPE_SPLASH_SCREEN) {
|
||||
addSplashScreenStartingWindow(windowInfo, 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(StartingWindowInfo windowInfo, IBinder appToken) {
|
||||
public void addSplashScreenStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
|
||||
final RunningTaskInfo taskInfo = windowInfo.taskInfo;
|
||||
final ActivityInfo activityInfo = taskInfo.topActivityInfo;
|
||||
if (activityInfo == null) {
|
||||
@@ -378,8 +268,8 @@ public class StartingSurfaceDrawer {
|
||||
/**
|
||||
* Called when a task need a snapshot starting window.
|
||||
*/
|
||||
private void makeTaskSnapshotWindow(StartingWindowInfo startingWindowInfo,
|
||||
IBinder appToken, TaskSnapshot snapshot) {
|
||||
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 */);
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* 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.window.StartingWindowInfo.STARTING_WINDOW_TYPE_NONE;
|
||||
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SNAPSHOT;
|
||||
import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
|
||||
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.ActivityTaskManager;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Slog;
|
||||
import android.window.StartingWindowInfo;
|
||||
import android.window.TaskOrganizer;
|
||||
import android.window.TaskSnapshot;
|
||||
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
|
||||
/**
|
||||
* Implementation to draw the starting window to an application, and remove the starting window
|
||||
* until the application displays its own window.
|
||||
*
|
||||
* When receive {@link TaskOrganizer#addStartingWindow} callback, use this class to create a
|
||||
* starting window and attached to the Task, then when the Task want to remove the starting window,
|
||||
* the TaskOrganizer will receive {@link TaskOrganizer#removeStartingWindow} callback then use this
|
||||
* class to remove the starting window of the Task.
|
||||
* @hide
|
||||
*/
|
||||
public class StartingWindowController {
|
||||
private static final String TAG = StartingWindowController.class.getSimpleName();
|
||||
static final boolean DEBUG_SPLASH_SCREEN = false;
|
||||
static final boolean DEBUG_TASK_SNAPSHOT = false;
|
||||
|
||||
private final StartingSurfaceDrawer mStartingSurfaceDrawer;
|
||||
private final StartingTypeChecker mStartingTypeChecker = new StartingTypeChecker();
|
||||
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
|
||||
|
||||
public StartingWindowController(Context context, ShellExecutor mainExecutor) {
|
||||
mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, mainExecutor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide the implementation for Shell Module.
|
||||
*/
|
||||
public StartingSurface asStartingSurface() {
|
||||
return mImpl;
|
||||
}
|
||||
|
||||
private static class StartingTypeChecker {
|
||||
TaskSnapshot mSnapshot;
|
||||
|
||||
StartingTypeChecker() { }
|
||||
|
||||
private void reset() {
|
||||
mSnapshot = null;
|
||||
}
|
||||
|
||||
private @StartingWindowInfo.StartingWindowType int
|
||||
estimateStartingWindowType(StartingWindowInfo windowInfo) {
|
||||
reset();
|
||||
final int parameter = windowInfo.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;
|
||||
return estimateStartingWindowType(windowInfo, newTask, taskSwitch,
|
||||
processRunning, allowTaskSnapshot, activityCreated);
|
||||
}
|
||||
|
||||
// reference from ActivityRecord#getStartingWindowType
|
||||
private int estimateStartingWindowType(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_WINDOW_TYPE_SPLASH_SCREEN;
|
||||
}
|
||||
if (taskSwitch && allowTaskSnapshot) {
|
||||
final TaskSnapshot snapshot = getTaskSnapshot(windowInfo.taskInfo.taskId);
|
||||
if (isSnapshotCompatible(windowInfo, snapshot)) {
|
||||
return STARTING_WINDOW_TYPE_SNAPSHOT;
|
||||
}
|
||||
if (windowInfo.taskInfo.topActivityType != ACTIVITY_TYPE_HOME) {
|
||||
return STARTING_WINDOW_TYPE_SPLASH_SCREEN;
|
||||
}
|
||||
}
|
||||
return STARTING_WINDOW_TYPE_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
|
||||
final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
|
||||
if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
|
||||
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
|
||||
} else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
|
||||
final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
|
||||
mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
|
||||
}
|
||||
// If prefer don't show, then don't show!
|
||||
}
|
||||
|
||||
void copySplashScreenView(int taskId) {
|
||||
mStartingSurfaceDrawer.copySplashScreenView(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the content of a task is ready to show, starting window can be removed.
|
||||
*/
|
||||
void removeStartingWindow(int taskId) {
|
||||
mStartingSurfaceDrawer.removeStartingWindow(taskId);
|
||||
}
|
||||
|
||||
private class StartingSurfaceImpl implements StartingSurface {
|
||||
|
||||
@Override
|
||||
public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
|
||||
StartingWindowController.this.addStartingWindow(windowInfo, appToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeStartingWindow(int taskId) {
|
||||
StartingWindowController.this.removeStartingWindow(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copySplashScreenView(int taskId) {
|
||||
StartingWindowController.this.copySplashScreenView(taskId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,6 @@ import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.TransactionPool;
|
||||
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
|
||||
import com.android.wm.shell.startingsurface.StartingSurfaceDrawer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -79,8 +78,6 @@ public class ShellTaskOrganizerTests {
|
||||
private Context mContext;
|
||||
@Mock
|
||||
private SizeCompatUIController mSizeCompatUI;
|
||||
@Mock
|
||||
private StartingSurfaceDrawer mStartingSurfaceDrawer;
|
||||
|
||||
ShellTaskOrganizer mOrganizer;
|
||||
private final SyncTransactionQueue mSyncTransactionQueue = mock(SyncTransactionQueue.class);
|
||||
@@ -116,7 +113,7 @@ public class ShellTaskOrganizerTests {
|
||||
.when(mTaskOrganizerController).registerTaskOrganizer(any());
|
||||
} catch (RemoteException e) {}
|
||||
mOrganizer = spy(new ShellTaskOrganizer(mTaskOrganizerController, mTestExecutor, mContext,
|
||||
mSizeCompatUI, mStartingSurfaceDrawer));
|
||||
mSizeCompatUI));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -125,7 +125,7 @@ public class StartingSurfaceDrawerTests {
|
||||
final Handler mainLoop = new Handler(Looper.getMainLooper());
|
||||
final StartingWindowInfo windowInfo =
|
||||
createWindowInfo(taskId, android.R.style.Theme);
|
||||
mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
|
||||
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
|
||||
waitHandlerIdle(mainLoop);
|
||||
verify(mStartingSurfaceDrawer).postAddWindow(
|
||||
eq(taskId), eq(mBinder), any(), any(), any(), any());
|
||||
@@ -143,7 +143,7 @@ public class StartingSurfaceDrawerTests {
|
||||
final Handler mainLoop = new Handler(Looper.getMainLooper());
|
||||
final StartingWindowInfo windowInfo =
|
||||
createWindowInfo(taskId, 0);
|
||||
mStartingSurfaceDrawer.addStartingWindow(windowInfo, mBinder);
|
||||
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder);
|
||||
waitHandlerIdle(mainLoop);
|
||||
verify(mStartingSurfaceDrawer).postAddWindow(
|
||||
eq(taskId), eq(mBinder), any(), any(), any(), any());
|
||||
|
||||
@@ -115,7 +115,8 @@ public class SystemUIFactory {
|
||||
.setShellCommandHandler(mWMComponent.getShellCommandHandler())
|
||||
.setAppPairs(mWMComponent.getAppPairs())
|
||||
.setTaskViewFactory(mWMComponent.getTaskViewFactory())
|
||||
.setTransitions(mWMComponent.getTransitions());
|
||||
.setTransitions(mWMComponent.getTransitions())
|
||||
.setStartingSurface(mWMComponent.getStartingSurface());
|
||||
} else {
|
||||
// TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
|
||||
// is separating this logic into newly creating SystemUITestsFactory.
|
||||
@@ -129,7 +130,8 @@ public class SystemUIFactory {
|
||||
.setShellCommandHandler(Optional.ofNullable(null))
|
||||
.setAppPairs(Optional.ofNullable(null))
|
||||
.setTaskViewFactory(Optional.ofNullable(null))
|
||||
.setTransitions(Transitions.createEmptyForTesting());
|
||||
.setTransitions(Transitions.createEmptyForTesting())
|
||||
.setStartingSurface(Optional.ofNullable(null));
|
||||
}
|
||||
mSysUIComponent = builder.build();
|
||||
if (initializeComponents) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.onehanded.OneHanded;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||
import com.android.wm.shell.transition.RemoteTransitions;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -88,6 +89,9 @@ public interface SysUIComponent {
|
||||
@BindsInstance
|
||||
Builder setTransitions(RemoteTransitions t);
|
||||
|
||||
@BindsInstance
|
||||
Builder setStartingSurface(Optional<StartingSurface> s);
|
||||
|
||||
SysUIComponent build();
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.onehanded.OneHanded;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||
import com.android.wm.shell.transition.RemoteTransitions;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -98,4 +99,7 @@ public interface WMComponent {
|
||||
|
||||
@WMSingleton
|
||||
RemoteTransitions getTransitions();
|
||||
|
||||
@WMSingleton
|
||||
Optional<StartingSurface> getStartingSurface();
|
||||
}
|
||||
|
||||
@@ -77,6 +77,8 @@ import com.android.wm.shell.pip.phone.PipTouchHandler;
|
||||
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
import com.android.wm.shell.startingsurface.StartingSurface;
|
||||
import com.android.wm.shell.startingsurface.StartingWindowController;
|
||||
import com.android.wm.shell.transition.RemoteTransitions;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
@@ -448,6 +450,22 @@ public abstract class WMShellBaseModule {
|
||||
@BindsOptionalOf
|
||||
abstract AppPairsController optionalAppPairs();
|
||||
|
||||
// Starting window
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<StartingSurface> provideStartingSurface(
|
||||
StartingWindowController startingWindowController) {
|
||||
return Optional.of(startingWindowController.asStartingSurface());
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static StartingWindowController provideStartingWindowController(Context context,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
return new StartingWindowController(context, mainExecutor);
|
||||
}
|
||||
|
||||
//
|
||||
// Task view factory
|
||||
//
|
||||
@@ -479,6 +497,7 @@ public abstract class WMShellBaseModule {
|
||||
Optional<LegacySplitScreenController> legacySplitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<AppPairsController> appPairsOptional,
|
||||
Optional<StartingSurface> startingSurface,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Transitions transitions,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
@@ -488,6 +507,7 @@ public abstract class WMShellBaseModule {
|
||||
legacySplitScreenOptional,
|
||||
splitScreenOptional,
|
||||
appPairsOptional,
|
||||
startingSurface,
|
||||
fullscreenTaskListener,
|
||||
transitions,
|
||||
mainExecutor);
|
||||
|
||||
Reference in New Issue
Block a user