Merge changes I06d26609,I0afbacd0 into sc-dev
* changes: 10/ Update split for shell thread 9/ Update transitions/starting window for shell thread
This commit is contained in:
@@ -25,6 +25,7 @@ import com.android.wm.shell.onehanded.OneHanded;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Optional;
|
||||
@@ -38,7 +39,7 @@ public final class ShellCommandHandlerImpl {
|
||||
private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();
|
||||
|
||||
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
|
||||
private final Optional<SplitScreen> mSplitScreenOptional;
|
||||
private final Optional<SplitScreenController> mSplitScreenOptional;
|
||||
private final Optional<Pip> mPipOptional;
|
||||
private final Optional<OneHanded> mOneHandedOptional;
|
||||
private final Optional<HideDisplayCutout> mHideDisplayCutout;
|
||||
@@ -50,7 +51,7 @@ public final class ShellCommandHandlerImpl {
|
||||
public static ShellCommandHandler create(
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
||||
Optional<SplitScreen> splitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<Pip> pipOptional,
|
||||
Optional<OneHanded> oneHandedOptional,
|
||||
Optional<HideDisplayCutout> hideDisplayCutout,
|
||||
@@ -64,7 +65,7 @@ public final class ShellCommandHandlerImpl {
|
||||
private ShellCommandHandlerImpl(
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
||||
Optional<SplitScreen> splitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<Pip> pipOptional,
|
||||
Optional<OneHanded> oneHandedOptional,
|
||||
Optional<HideDisplayCutout> hideDisplayCutout,
|
||||
|
||||
@@ -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.LegacySplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -39,7 +40,7 @@ public class ShellInitImpl {
|
||||
private final DragAndDropController mDragAndDropController;
|
||||
private final ShellTaskOrganizer mShellTaskOrganizer;
|
||||
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
|
||||
private final Optional<SplitScreen> mSplitScreenOptional;
|
||||
private final Optional<SplitScreenController> mSplitScreenOptional;
|
||||
private final Optional<AppPairs> mAppPairsOptional;
|
||||
private final FullscreenTaskListener mFullscreenTaskListener;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
@@ -51,7 +52,7 @@ public class ShellInitImpl {
|
||||
DragAndDropController dragAndDropController,
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
||||
Optional<SplitScreen> splitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<AppPairs> appPairsOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Transitions transitions,
|
||||
@@ -71,7 +72,7 @@ public class ShellInitImpl {
|
||||
DragAndDropController dragAndDropController,
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
||||
Optional<SplitScreen> splitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<AppPairs> appPairsOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Transitions transitions,
|
||||
@@ -97,7 +98,7 @@ public class ShellInitImpl {
|
||||
mShellTaskOrganizer.registerOrganizer();
|
||||
|
||||
mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered);
|
||||
mSplitScreenOptional.ifPresent(SplitScreen::onOrganizerRegistered);
|
||||
mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered);
|
||||
|
||||
// Bind the splitscreen impl to the drag drop controller
|
||||
mDragAndDropController.initialize(mSplitScreenOptional);
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -66,7 +67,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
|
||||
|
||||
private final Context mContext;
|
||||
private final DisplayController mDisplayController;
|
||||
private SplitScreen mSplitScreen;
|
||||
private SplitScreenController mSplitScreen;
|
||||
|
||||
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
|
||||
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
|
||||
@@ -76,7 +77,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
|
||||
mDisplayController = displayController;
|
||||
}
|
||||
|
||||
public void initialize(Optional<SplitScreen> splitscreen) {
|
||||
public void initialize(Optional<SplitScreenController> splitscreen) {
|
||||
mSplitScreen = splitscreen.orElse(null);
|
||||
mDisplayController.addDisplayWindowListener(this);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen.StagePosition;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen.StageType;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -81,18 +83,18 @@ public class DragAndDropPolicy {
|
||||
private final Context mContext;
|
||||
private final ActivityTaskManager mActivityTaskManager;
|
||||
private final Starter mStarter;
|
||||
private final SplitScreen mSplitScreen;
|
||||
private final SplitScreenController mSplitScreen;
|
||||
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
|
||||
|
||||
private DragSession mSession;
|
||||
|
||||
public DragAndDropPolicy(Context context, SplitScreen splitScreen) {
|
||||
public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
|
||||
this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
|
||||
SplitScreen splitScreen, Starter starter) {
|
||||
SplitScreenController splitScreen, Starter starter) {
|
||||
mContext = context;
|
||||
mActivityTaskManager = activityTaskManager;
|
||||
mSplitScreen = splitScreen;
|
||||
@@ -200,8 +202,8 @@ public class DragAndDropPolicy {
|
||||
final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible();
|
||||
final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT;
|
||||
|
||||
@SplitScreen.StageType int stage = STAGE_TYPE_UNDEFINED;
|
||||
@SplitScreen.StagePosition int position = STAGE_POSITION_UNDEFINED;
|
||||
@StageType int stage = STAGE_TYPE_UNDEFINED;
|
||||
@StagePosition int position = STAGE_POSITION_UNDEFINED;
|
||||
if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) {
|
||||
// Update launch options for the split side we are targeting.
|
||||
position = leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
|
||||
@@ -213,7 +215,28 @@ public class DragAndDropPolicy {
|
||||
|
||||
final ClipDescription description = data.getDescription();
|
||||
final Intent dragData = mSession.dragData;
|
||||
mStarter.startClipDescription(description, dragData, stage, position);
|
||||
startClipDescription(description, dragData, stage, position);
|
||||
}
|
||||
|
||||
private void startClipDescription(ClipDescription description, Intent intent,
|
||||
@StageType int stage, @StagePosition int position) {
|
||||
final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
|
||||
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
|
||||
final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
|
||||
? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle();
|
||||
|
||||
if (isTask) {
|
||||
final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
|
||||
mStarter.startTask(taskId, stage, position, opts);
|
||||
} else if (isShortcut) {
|
||||
final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
|
||||
final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID);
|
||||
final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
|
||||
mStarter.startShortcut(packageName, id, stage, position, opts, user);
|
||||
} else {
|
||||
mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position,
|
||||
opts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,34 +290,13 @@ public class DragAndDropPolicy {
|
||||
/**
|
||||
* Interface for actually committing the task launches.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public interface Starter {
|
||||
default void startClipDescription(ClipDescription description, Intent intent,
|
||||
@SplitScreen.StageType int stage, @SplitScreen.StagePosition int position) {
|
||||
final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK);
|
||||
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT);
|
||||
final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS)
|
||||
? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle();
|
||||
|
||||
if (isTask) {
|
||||
final int taskId = intent.getIntExtra(EXTRA_TASK_ID, INVALID_TASK_ID);
|
||||
startTask(taskId, stage, position, opts);
|
||||
} else if (isShortcut) {
|
||||
final String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);
|
||||
final String id = intent.getStringExtra(EXTRA_SHORTCUT_ID);
|
||||
final UserHandle user = intent.getParcelableExtra(EXTRA_USER);
|
||||
startShortcut(packageName, id, stage, position, opts, user);
|
||||
} else {
|
||||
startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT), stage, position, opts);
|
||||
}
|
||||
}
|
||||
void startTask(int taskId, @SplitScreen.StageType int stage,
|
||||
@SplitScreen.StagePosition int position, @Nullable Bundle options);
|
||||
void startShortcut(String packageName, String shortcutId,
|
||||
@SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
|
||||
@Nullable Bundle options, UserHandle user);
|
||||
void startIntent(PendingIntent intent, @SplitScreen.StageType int stage,
|
||||
@SplitScreen.StagePosition int position, @Nullable Bundle options);
|
||||
void startTask(int taskId, @StageType int stage, @StagePosition int position,
|
||||
@Nullable Bundle options);
|
||||
void startShortcut(String packageName, String shortcutId, @StageType int stage,
|
||||
@StagePosition int position, @Nullable Bundle options, UserHandle user);
|
||||
void startIntent(PendingIntent intent, @StageType int stage, @StagePosition int position,
|
||||
@Nullable Bundle options);
|
||||
void enterSplitScreen(int taskId, boolean leftOrTop);
|
||||
void exitSplitScreen();
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -61,7 +61,7 @@ public class DragLayout extends View {
|
||||
private boolean mIsShowing;
|
||||
private boolean mHasDropped;
|
||||
|
||||
public DragLayout(Context context, SplitScreen splitscreen) {
|
||||
public DragLayout(Context context, SplitScreenController splitscreen) {
|
||||
super(context);
|
||||
mPolicy = new DragAndDropPolicy(context, splitscreen);
|
||||
mDisplayMargin = context.getResources().getDimensionPixelSize(
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Interface to engage split-screen feature.
|
||||
* TODO: Figure out which of these are actually needed outside of the Shell
|
||||
*/
|
||||
@ExternalThread
|
||||
public interface SplitScreen extends DragAndDropPolicy.Starter {
|
||||
@@ -102,18 +103,11 @@ public interface SplitScreen extends DragAndDropPolicy.Starter {
|
||||
void setSideStagePosition(@StagePosition int sideStagePosition);
|
||||
/** Hides the side-stage if it is currently visible. */
|
||||
void setSideStageVisibility(boolean visible);
|
||||
default void enterSplitScreen(int taskId, boolean leftOrTop) {
|
||||
moveToSideStage(taskId,
|
||||
leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT);
|
||||
}
|
||||
|
||||
/** Removes the split-screen stages. */
|
||||
void exitSplitScreen();
|
||||
/** Gets the stage bounds. */
|
||||
void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds);
|
||||
/** Dumps current status of split-screen. */
|
||||
void dump(@NonNull PrintWriter pw, String prefix);
|
||||
/** Called when the shell organizer has been registered. */
|
||||
void onOrganizerRegistered();
|
||||
|
||||
void registerSplitScreenListener(SplitScreenListener listener);
|
||||
void unregisterSplitScreenListener(SplitScreenListener listener);
|
||||
|
||||
@@ -18,6 +18,13 @@ package com.android.wm.shell.splitscreen;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_BOTTOM_OR_RIGHT;
|
||||
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_TOP_OR_LEFT;
|
||||
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_POSITION_UNDEFINED;
|
||||
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
|
||||
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
|
||||
import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityTaskManager;
|
||||
import android.app.PendingIntent;
|
||||
@@ -35,7 +42,9 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@@ -44,25 +53,33 @@ import java.io.PrintWriter;
|
||||
* {@link SplitScreen}.
|
||||
* @see StageCoordinator
|
||||
*/
|
||||
public class SplitScreenController implements SplitScreen {
|
||||
public class SplitScreenController implements DragAndDropPolicy.Starter {
|
||||
private static final String TAG = SplitScreenController.class.getSimpleName();
|
||||
|
||||
private final ShellTaskOrganizer mTaskOrganizer;
|
||||
private final SyncTransactionQueue mSyncQueue;
|
||||
private final Context mContext;
|
||||
private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private final SplitScreenImpl mImpl = new SplitScreenImpl();
|
||||
|
||||
private StageCoordinator mStageCoordinator;
|
||||
|
||||
public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
|
||||
SyncTransactionQueue syncQueue, Context context,
|
||||
RootTaskDisplayAreaOrganizer rootTDAOrganizer) {
|
||||
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
|
||||
ShellExecutor mainExecutor) {
|
||||
mTaskOrganizer = shellTaskOrganizer;
|
||||
mSyncQueue = syncQueue;
|
||||
mContext = context;
|
||||
mRootTDAOrganizer = rootTDAOrganizer;
|
||||
mMainExecutor = mainExecutor;
|
||||
}
|
||||
|
||||
public SplitScreen asSplitScreen() {
|
||||
return mImpl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOrganizerRegistered() {
|
||||
if (mStageCoordinator == null) {
|
||||
// TODO: Multi-display
|
||||
@@ -71,13 +88,11 @@ public class SplitScreenController implements SplitScreen {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSplitScreenVisible() {
|
||||
return mStageCoordinator.isSplitScreenVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition) {
|
||||
public boolean moveToSideStage(int taskId, @SplitScreen.StagePosition int sideStagePosition) {
|
||||
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
|
||||
if (task == null) {
|
||||
throw new IllegalArgumentException("Unknown taskId" + taskId);
|
||||
@@ -85,50 +100,46 @@ public class SplitScreenController implements SplitScreen {
|
||||
return moveToSideStage(task, sideStagePosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
|
||||
@StagePosition int sideStagePosition) {
|
||||
@SplitScreen.StagePosition int sideStagePosition) {
|
||||
return mStageCoordinator.moveToSideStage(task, sideStagePosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFromSideStage(int taskId) {
|
||||
return mStageCoordinator.removeFromSideStage(taskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSideStagePosition(@StagePosition int sideStagePosition) {
|
||||
public void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) {
|
||||
mStageCoordinator.setSideStagePosition(sideStagePosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSideStageVisibility(boolean visible) {
|
||||
mStageCoordinator.setSideStageVisibility(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSplitScreen(int taskId, boolean leftOrTop) {
|
||||
moveToSideStage(taskId,
|
||||
leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT);
|
||||
}
|
||||
|
||||
public void exitSplitScreen() {
|
||||
mStageCoordinator.exitSplitScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
|
||||
mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSplitScreenListener(SplitScreenListener listener) {
|
||||
public void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
|
||||
mStageCoordinator.registerSplitScreenListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterSplitScreenListener(SplitScreenListener listener) {
|
||||
public void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) {
|
||||
mStageCoordinator.unregisterSplitScreenListener(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTask(int taskId,
|
||||
@StageType int stage, @StagePosition int position, @Nullable Bundle options) {
|
||||
public void startTask(int taskId, @SplitScreen.StageType int stage,
|
||||
@SplitScreen.StagePosition int position, @Nullable Bundle options) {
|
||||
options = resolveStartStage(stage, position, options);
|
||||
|
||||
try {
|
||||
@@ -138,9 +149,9 @@ public class SplitScreenController implements SplitScreen {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startShortcut(String packageName, String shortcutId, @StageType int stage,
|
||||
@StagePosition int position, @Nullable Bundle options, UserHandle user) {
|
||||
public void startShortcut(String packageName, String shortcutId,
|
||||
@SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
|
||||
@Nullable Bundle options, UserHandle user) {
|
||||
options = resolveStartStage(stage, position, options);
|
||||
|
||||
try {
|
||||
@@ -153,9 +164,8 @@ public class SplitScreenController implements SplitScreen {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startIntent(PendingIntent intent,
|
||||
@StageType int stage, @StagePosition int position, @Nullable Bundle options) {
|
||||
public void startIntent(PendingIntent intent, @SplitScreen.StageType int stage,
|
||||
@SplitScreen.StagePosition int position, @Nullable Bundle options) {
|
||||
options = resolveStartStage(stage, position, options);
|
||||
|
||||
try {
|
||||
@@ -165,8 +175,8 @@ public class SplitScreenController implements SplitScreen {
|
||||
}
|
||||
}
|
||||
|
||||
private Bundle resolveStartStage(@StageType int stage, @StagePosition int position,
|
||||
@Nullable Bundle options) {
|
||||
private Bundle resolveStartStage(@SplitScreen.StageType int stage,
|
||||
@SplitScreen.StagePosition int position, @Nullable Bundle options) {
|
||||
switch (stage) {
|
||||
case STAGE_TYPE_UNDEFINED: {
|
||||
// Use the stage of the specified position is valid.
|
||||
@@ -216,7 +226,6 @@ public class SplitScreenController implements SplitScreen {
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(@NonNull PrintWriter pw, String prefix) {
|
||||
pw.println(prefix + TAG);
|
||||
if (mStageCoordinator != null) {
|
||||
@@ -224,4 +233,113 @@ public class SplitScreenController implements SplitScreen {
|
||||
}
|
||||
}
|
||||
|
||||
private class SplitScreenImpl implements SplitScreen {
|
||||
@Override
|
||||
public boolean isSplitScreenVisible() {
|
||||
return mMainExecutor.executeBlockingForResult(() -> {
|
||||
return SplitScreenController.this.isSplitScreenVisible();
|
||||
}, Boolean.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToSideStage(int taskId, int sideStagePosition) {
|
||||
return mMainExecutor.executeBlockingForResult(() -> {
|
||||
return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition);
|
||||
}, Boolean.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
|
||||
int sideStagePosition) {
|
||||
return mMainExecutor.executeBlockingForResult(() -> {
|
||||
return SplitScreenController.this.moveToSideStage(task, sideStagePosition);
|
||||
}, Boolean.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFromSideStage(int taskId) {
|
||||
return mMainExecutor.executeBlockingForResult(() -> {
|
||||
return SplitScreenController.this.removeFromSideStage(taskId);
|
||||
}, Boolean.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSideStagePosition(int sideStagePosition) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.setSideStagePosition(sideStagePosition);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSideStageVisibility(boolean visible) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.setSideStageVisibility(visible);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enterSplitScreen(int taskId, boolean leftOrTop) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.enterSplitScreen(taskId, leftOrTop);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exitSplitScreen() {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.exitSplitScreen();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
|
||||
try {
|
||||
mMainExecutor.executeBlocking(() -> {
|
||||
SplitScreenController.this.getStageBounds(outTopOrLeftBounds,
|
||||
outBottomOrRightBounds);
|
||||
});
|
||||
} catch (InterruptedException e) {
|
||||
Slog.e(TAG, "Failed to get stage bounds in 2s");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSplitScreenListener(SplitScreenListener listener) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.registerSplitScreenListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterSplitScreenListener(SplitScreenListener listener) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.unregisterSplitScreenListener(listener);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startTask(int taskId, int stage, int position, @Nullable Bundle options) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.startTask(taskId, stage, position, options);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startShortcut(String packageName, String shortcutId, int stage, int position,
|
||||
@Nullable Bundle options, UserHandle user) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.startShortcut(packageName, shortcutId, stage, position,
|
||||
options, user);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startIntent(PendingIntent intent, int stage, int position,
|
||||
@Nullable Bundle options) {
|
||||
mMainExecutor.execute(() -> {
|
||||
SplitScreenController.this.startIntent(intent, stage, position, options);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -377,12 +377,10 @@ public class StartingSurfaceDrawer {
|
||||
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);
|
||||
});
|
||||
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
|
||||
final StartingWindowRecord tView =
|
||||
new StartingWindowRecord(null/* decorView */, surface);
|
||||
mStartingWindowRecords.put(taskId, tView);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -392,42 +390,40 @@ public class StartingSurfaceDrawer {
|
||||
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
|
||||
Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId);
|
||||
}
|
||||
mMainExecutor.execute(() -> removeWindowSynced(taskId));
|
||||
removeWindowSynced(taskId);
|
||||
}
|
||||
|
||||
protected void postAddWindow(int taskId, IBinder appToken,
|
||||
View view, WindowManager wm, WindowManager.LayoutParams params) {
|
||||
mMainExecutor.execute(() -> {
|
||||
boolean shouldSaveView = true;
|
||||
try {
|
||||
wm.addView(view, params);
|
||||
} catch (WindowManager.BadTokenException e) {
|
||||
// ignore
|
||||
Slog.w(TAG, appToken + " already running, starting window not displayed. "
|
||||
+ e.getMessage());
|
||||
View view, WindowManager wm, WindowManager.LayoutParams params) {
|
||||
boolean shouldSaveView = true;
|
||||
try {
|
||||
wm.addView(view, params);
|
||||
} catch (WindowManager.BadTokenException e) {
|
||||
// ignore
|
||||
Slog.w(TAG, appToken + " already running, starting window not displayed. "
|
||||
+ e.getMessage());
|
||||
shouldSaveView = false;
|
||||
} catch (RuntimeException e) {
|
||||
// don't crash if something else bad happens, for example a
|
||||
// failure loading resources because we are loading from an app
|
||||
// on external storage that has been unmounted.
|
||||
Slog.w(TAG, appToken + " failed creating starting window", e);
|
||||
shouldSaveView = false;
|
||||
} finally {
|
||||
if (view != null && view.getParent() == null) {
|
||||
Slog.w(TAG, "view not successfully added to wm, removing view");
|
||||
wm.removeViewImmediate(view);
|
||||
shouldSaveView = false;
|
||||
} catch (RuntimeException e) {
|
||||
// don't crash if something else bad happens, for example a
|
||||
// failure loading resources because we are loading from an app
|
||||
// on external storage that has been unmounted.
|
||||
Slog.w(TAG, appToken + " failed creating starting window", e);
|
||||
shouldSaveView = false;
|
||||
} finally {
|
||||
if (view != null && view.getParent() == null) {
|
||||
Slog.w(TAG, "view not successfully added to wm, removing view");
|
||||
wm.removeViewImmediate(view);
|
||||
shouldSaveView = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldSaveView) {
|
||||
removeWindowSynced(taskId);
|
||||
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
|
||||
final StartingWindowRecord tView =
|
||||
new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
|
||||
mStartingWindowRecords.put(taskId, tView);
|
||||
}
|
||||
});
|
||||
if (shouldSaveView) {
|
||||
removeWindowSynced(taskId);
|
||||
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
|
||||
final StartingWindowRecord tView =
|
||||
new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
|
||||
mStartingWindowRecords.put(taskId, tView);
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeWindowSynced(int taskId) {
|
||||
@@ -445,7 +441,7 @@ public class StartingSurfaceDrawer {
|
||||
if (DEBUG_TASK_SNAPSHOT) {
|
||||
Slog.v(TAG, "Removing task snapshot window for " + taskId);
|
||||
}
|
||||
record.mTaskSnapshotWindow.remove(mMainExecutor);
|
||||
record.mTaskSnapshotWindow.remove();
|
||||
}
|
||||
mStartingWindowRecords.remove(taskId);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ 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;
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
|
||||
/**
|
||||
* This class represents a starting window that shows a snapshot.
|
||||
@@ -121,6 +122,7 @@ public class TaskSnapshotWindow {
|
||||
private final Window mWindow;
|
||||
private final Surface mSurface;
|
||||
private final Runnable mClearWindowHandler;
|
||||
private final ShellExecutor mMainExecutor;
|
||||
private SurfaceControl mSurfaceControl;
|
||||
private SurfaceControl mChildSurfaceControl;
|
||||
private final IWindowSession mSession;
|
||||
@@ -213,7 +215,7 @@ public class TaskSnapshotWindow {
|
||||
final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
|
||||
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
|
||||
windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
|
||||
topWindowInsetsState, clearWindowHandler);
|
||||
topWindowInsetsState, clearWindowHandler, mainExecutor);
|
||||
final Window window = snapshotSurface.mWindow;
|
||||
|
||||
final InsetsState mTmpInsetsState = new InsetsState();
|
||||
@@ -229,7 +231,7 @@ public class TaskSnapshotWindow {
|
||||
} catch (RemoteException e) {
|
||||
snapshotSurface.clearWindowSynced();
|
||||
}
|
||||
window.setOuter(snapshotSurface, mainExecutor);
|
||||
window.setOuter(snapshotSurface);
|
||||
try {
|
||||
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
|
||||
tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
|
||||
@@ -249,7 +251,8 @@ public class TaskSnapshotWindow {
|
||||
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
|
||||
int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
|
||||
int currentOrientation, int activityType, InsetsState topWindowInsetsState,
|
||||
Runnable clearWindowHandler) {
|
||||
Runnable clearWindowHandler, ShellExecutor mainExecutor) {
|
||||
mMainExecutor = mainExecutor;
|
||||
mSurface = new Surface();
|
||||
mSession = WindowManagerGlobal.getWindowSession();
|
||||
mWindow = new Window();
|
||||
@@ -286,28 +289,26 @@ public class TaskSnapshotWindow {
|
||||
mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
|
||||
}
|
||||
|
||||
void remove(ShellExecutor mainExecutor) {
|
||||
void remove() {
|
||||
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);
|
||||
mMainExecutor.executeDelayed(() -> remove(), 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
|
||||
try {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
|
||||
}
|
||||
});
|
||||
mSession.remove(mWindow);
|
||||
} catch (RemoteException e) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -497,13 +498,12 @@ public class TaskSnapshotWindow {
|
||||
}
|
||||
}
|
||||
|
||||
@ExternalThread
|
||||
static class Window extends BaseIWindow {
|
||||
private TaskSnapshotWindow mOuter;
|
||||
private ShellExecutor mMainExecutor;
|
||||
|
||||
public void setOuter(TaskSnapshotWindow outer, ShellExecutor mainExecutor) {
|
||||
public void setOuter(TaskSnapshotWindow outer) {
|
||||
mOuter = outer;
|
||||
mMainExecutor = mainExecutor;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -511,22 +511,20 @@ public class TaskSnapshotWindow {
|
||||
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.mMainExecutor.execute(() -> {
|
||||
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.
|
||||
mOuter.clearWindowSynced();
|
||||
});
|
||||
} else if (reportDraw) {
|
||||
mMainExecutor.execute(() -> {
|
||||
} else if (reportDraw) {
|
||||
if (mOuter.mHasDrawn) {
|
||||
mOuter.reportDrawn();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.transition;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.window.IRemoteTransition;
|
||||
import android.window.TransitionFilter;
|
||||
|
||||
import com.android.wm.shell.common.annotations.ExternalThread;
|
||||
|
||||
/**
|
||||
* Interface to manage remote transitions.
|
||||
*/
|
||||
@ExternalThread
|
||||
public interface RemoteTransitions {
|
||||
/**
|
||||
* Registers a remote transition.
|
||||
*/
|
||||
void registerRemote(@NonNull TransitionFilter filter,
|
||||
@NonNull IRemoteTransition remoteTransition);
|
||||
|
||||
/**
|
||||
* Unregisters a remote transition.
|
||||
*/
|
||||
void unregisterRemote(@NonNull IRemoteTransition remoteTransition);
|
||||
}
|
||||
@@ -67,6 +67,7 @@ public class Transitions {
|
||||
private final ShellExecutor mAnimExecutor;
|
||||
private final TransitionPlayerImpl mPlayerImpl;
|
||||
private final RemoteTransitionHandler mRemoteTransitionHandler;
|
||||
private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
|
||||
|
||||
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
|
||||
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
|
||||
@@ -78,6 +79,10 @@ public class Transitions {
|
||||
/** Keeps track of currently tracked transitions and all the animations associated with each */
|
||||
private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>();
|
||||
|
||||
public static RemoteTransitions asRemoteTransitions(Transitions transitions) {
|
||||
return transitions.mImpl;
|
||||
}
|
||||
|
||||
public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
|
||||
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
|
||||
mOrganizer = organizer;
|
||||
@@ -101,8 +106,20 @@ public class Transitions {
|
||||
|
||||
/** Create an empty/non-registering transitions object for system-ui tests. */
|
||||
@VisibleForTesting
|
||||
public static Transitions createEmptyForTesting() {
|
||||
return new Transitions();
|
||||
public static RemoteTransitions createEmptyForTesting() {
|
||||
return new RemoteTransitions() {
|
||||
@Override
|
||||
public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
|
||||
@androidx.annotation.NonNull IRemoteTransition remoteTransition) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterRemote(
|
||||
@androidx.annotation.NonNull IRemoteTransition remoteTransition) {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Register this transition handler with Core */
|
||||
@@ -134,16 +151,14 @@ public class Transitions {
|
||||
}
|
||||
|
||||
/** Register a remote transition to be used when `filter` matches an incoming transition */
|
||||
@ExternalThread
|
||||
public void registerRemote(@NonNull TransitionFilter filter,
|
||||
@NonNull IRemoteTransition remoteTransition) {
|
||||
mMainExecutor.execute(() -> mRemoteTransitionHandler.addFiltered(filter, remoteTransition));
|
||||
mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
|
||||
}
|
||||
|
||||
/** Unregisters a remote transition and all associated filters */
|
||||
@ExternalThread
|
||||
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
|
||||
mMainExecutor.execute(() -> mRemoteTransitionHandler.removeFiltered(remoteTransition));
|
||||
mRemoteTransitionHandler.removeFiltered(remoteTransition);
|
||||
}
|
||||
|
||||
/** @return true if the transition was triggered by opening something vs closing something */
|
||||
@@ -371,4 +386,22 @@ public class Transitions {
|
||||
mMainExecutor.execute(() -> Transitions.this.requestStartTransition(iBinder, request));
|
||||
}
|
||||
}
|
||||
|
||||
@ExternalThread
|
||||
private class RemoteTransitionImpl implements RemoteTransitions {
|
||||
@Override
|
||||
public void registerRemote(@NonNull TransitionFilter filter,
|
||||
@NonNull IRemoteTransition remoteTransition) {
|
||||
mMainExecutor.execute(() -> {
|
||||
Transitions.this.registerRemote(filter, remoteTransition);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
|
||||
mMainExecutor.execute(() -> {
|
||||
Transitions.this.unregisterRemote(remoteTransition);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
@@ -65,7 +66,7 @@ import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.wm.shell.common.DisplayLayout;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.splitscreen.SplitScreenController;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -92,7 +93,7 @@ public class DragAndDropPolicyTest {
|
||||
|
||||
// Both the split-screen and start interface.
|
||||
@Mock
|
||||
private SplitScreen mSplitScreenStarter;
|
||||
private SplitScreenController mSplitScreenStarter;
|
||||
|
||||
private DisplayLayout mLandscapeDisplayLayout;
|
||||
private DisplayLayout mPortraitDisplayLayout;
|
||||
@@ -127,8 +128,8 @@ public class DragAndDropPolicyTest {
|
||||
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
|
||||
mInsets = Insets.of(0, 0, 0, 0);
|
||||
|
||||
mPolicy = new DragAndDropPolicy(
|
||||
mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter);
|
||||
mPolicy = spy(new DragAndDropPolicy(
|
||||
mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter));
|
||||
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
|
||||
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
|
||||
setClipDataResizeable(mNonResizeableActivityClipData, false);
|
||||
@@ -204,8 +205,8 @@ public class DragAndDropPolicyTest {
|
||||
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -216,13 +217,13 @@ public class DragAndDropPolicyTest {
|
||||
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
|
||||
reset(mSplitScreenStarter);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -233,13 +234,13 @@ public class DragAndDropPolicyTest {
|
||||
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
|
||||
reset(mSplitScreenStarter);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -250,8 +251,8 @@ public class DragAndDropPolicyTest {
|
||||
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -262,8 +263,8 @@ public class DragAndDropPolicyTest {
|
||||
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -275,14 +276,14 @@ public class DragAndDropPolicyTest {
|
||||
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
|
||||
reset(mSplitScreenStarter);
|
||||
|
||||
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -294,14 +295,14 @@ public class DragAndDropPolicyTest {
|
||||
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
|
||||
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
|
||||
reset(mSplitScreenStarter);
|
||||
|
||||
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
|
||||
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
|
||||
verify(mSplitScreenStarter).startClipDescription(any(), any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT));
|
||||
verify(mSplitScreenStarter).startIntent(any(),
|
||||
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -47,6 +47,7 @@ import android.window.TaskSnapshot;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.wm.shell.TestShellExecutor;
|
||||
import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -83,7 +84,7 @@ public class TaskSnapshotWindowTest {
|
||||
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
|
||||
0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
|
||||
taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(),
|
||||
null /* clearWindow */);
|
||||
null /* clearWindow */, new TestShellExecutor());
|
||||
}
|
||||
|
||||
private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
|
||||
|
||||
@@ -33,7 +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.transition.Transitions;
|
||||
import com.android.wm.shell.transition.RemoteTransitions;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -86,7 +86,7 @@ public interface SysUIComponent {
|
||||
Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
|
||||
|
||||
@BindsInstance
|
||||
Builder setTransitions(Transitions t);
|
||||
Builder setTransitions(RemoteTransitions t);
|
||||
|
||||
SysUIComponent build();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,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.transition.Transitions;
|
||||
import com.android.wm.shell.transition.RemoteTransitions;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -55,16 +55,12 @@ public interface WMComponent {
|
||||
getShellInit().init();
|
||||
}
|
||||
|
||||
// Gets the Shell init instance
|
||||
@WMSingleton
|
||||
ShellInit getShellInit();
|
||||
|
||||
// Gets the Shell dump instance
|
||||
@WMSingleton
|
||||
Optional<ShellCommandHandler> getShellCommandHandler();
|
||||
|
||||
// TODO(b/162923491): We currently pass the instances through to SysUI, but that may change
|
||||
// depending on the threading mechanism we go with
|
||||
@WMSingleton
|
||||
Optional<OneHanded> getOneHanded();
|
||||
|
||||
@@ -89,7 +85,6 @@ public interface WMComponent {
|
||||
@WMSingleton
|
||||
Optional<TaskViewFactory> getTaskViewFactory();
|
||||
|
||||
/** Gets transitions */
|
||||
@WMSingleton
|
||||
Transitions getTransitions();
|
||||
RemoteTransitions getTransitions();
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ import com.android.wm.shell.onehanded.OneHanded;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.pip.PipAnimationController;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
import com.android.wm.shell.transition.RemoteTransitions;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -149,7 +149,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
||||
private final ScreenshotHelper mScreenshotHelper;
|
||||
private final Optional<OneHanded> mOneHandedOptional;
|
||||
private final CommandQueue mCommandQueue;
|
||||
private final Transitions mShellTransitions;
|
||||
private final RemoteTransitions mShellTransitions;
|
||||
|
||||
private Region mActiveNavBarRegion;
|
||||
|
||||
@@ -799,7 +799,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
|
||||
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
|
||||
Optional<OneHanded> oneHandedOptional,
|
||||
BroadcastDispatcher broadcastDispatcher,
|
||||
Transitions shellTransitions) {
|
||||
RemoteTransitions shellTransitions) {
|
||||
super(broadcastDispatcher);
|
||||
mContext = context;
|
||||
mPipOptional = pipOptional;
|
||||
|
||||
@@ -75,6 +75,7 @@ import com.android.wm.shell.sizecompatui.SizeCompatUI;
|
||||
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.transition.RemoteTransitions;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
import java.util.Optional;
|
||||
@@ -179,7 +180,7 @@ public abstract class WMShellBaseModule {
|
||||
DragAndDropController dragAndDropController,
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
||||
Optional<SplitScreen> splitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<AppPairs> appPairsOptional,
|
||||
FullscreenTaskListener fullscreenTaskListener,
|
||||
Transitions transitions,
|
||||
@@ -204,7 +205,7 @@ public abstract class WMShellBaseModule {
|
||||
static Optional<ShellCommandHandler> provideShellCommandHandler(
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
Optional<LegacySplitScreen> legacySplitScreenOptional,
|
||||
Optional<SplitScreen> splitScreenOptional,
|
||||
Optional<SplitScreenController> splitScreenOptional,
|
||||
Optional<Pip> pipOptional,
|
||||
Optional<OneHanded> oneHandedOptional,
|
||||
Optional<HideDisplayCutout> hideDisplayCutout,
|
||||
@@ -319,12 +320,21 @@ public abstract class WMShellBaseModule {
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<SplitScreen> provideSplitScreen(ShellTaskOrganizer shellTaskOrganizer,
|
||||
static Optional<SplitScreen> provideSplitScreen(
|
||||
Optional<SplitScreenController> splitScreenController) {
|
||||
return splitScreenController.map((controller) -> controller.asSplitScreen());
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<SplitScreenController> provideSplitScreenController(
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
SyncTransactionQueue syncQueue, Context context,
|
||||
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
|
||||
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
|
||||
@ShellMainThread ShellExecutor mainExecutor) {
|
||||
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
|
||||
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
|
||||
rootTaskDisplayAreaOrganizer));
|
||||
rootTaskDisplayAreaOrganizer, mainExecutor));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -386,6 +396,12 @@ public abstract class WMShellBaseModule {
|
||||
return new FullscreenTaskListener(syncQueue);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
|
||||
return Transitions.asRemoteTransitions(transitions);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,
|
||||
|
||||
@@ -43,7 +43,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
|
||||
import com.android.wm.shell.pip.Pip;
|
||||
import com.android.wm.shell.splitscreen.SplitScreen;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
import com.android.wm.shell.transition.RemoteTransitions;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -78,7 +78,7 @@ public class OverviewProxyServiceTest extends SysuiTestCase {
|
||||
@Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
|
||||
@Mock private PackageManager mPackageManager;
|
||||
@Mock private SysUiState mMockSysUiState;
|
||||
@Mock private Transitions mMockTransitions;
|
||||
@Mock private RemoteTransitions mMockTransitions;
|
||||
|
||||
@Before
|
||||
public void setUp() throws RemoteException {
|
||||
|
||||
Reference in New Issue
Block a user