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:
Winson Chung
2021-02-09 06:40:57 +00:00
committed by Android (Google) Code Review
18 changed files with 398 additions and 201 deletions

View File

@@ -25,6 +25,7 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Optional; import java.util.Optional;
@@ -38,7 +39,7 @@ public final class ShellCommandHandlerImpl {
private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName(); private static final String TAG = ShellCommandHandlerImpl.class.getSimpleName();
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional; private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<SplitScreen> mSplitScreenOptional; private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<Pip> mPipOptional; private final Optional<Pip> mPipOptional;
private final Optional<OneHanded> mOneHandedOptional; private final Optional<OneHanded> mOneHandedOptional;
private final Optional<HideDisplayCutout> mHideDisplayCutout; private final Optional<HideDisplayCutout> mHideDisplayCutout;
@@ -50,7 +51,7 @@ public final class ShellCommandHandlerImpl {
public static ShellCommandHandler create( public static ShellCommandHandler create(
ShellTaskOrganizer shellTaskOrganizer, ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional, Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional, Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional, Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout, Optional<HideDisplayCutout> hideDisplayCutout,
@@ -64,7 +65,7 @@ public final class ShellCommandHandlerImpl {
private ShellCommandHandlerImpl( private ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer, ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional, Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional, Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional, Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout, Optional<HideDisplayCutout> hideDisplayCutout,

View File

@@ -25,6 +25,7 @@ import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropController; import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.transition.Transitions;
import java.util.Optional; import java.util.Optional;
@@ -39,7 +40,7 @@ public class ShellInitImpl {
private final DragAndDropController mDragAndDropController; private final DragAndDropController mDragAndDropController;
private final ShellTaskOrganizer mShellTaskOrganizer; private final ShellTaskOrganizer mShellTaskOrganizer;
private final Optional<LegacySplitScreen> mLegacySplitScreenOptional; private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
private final Optional<SplitScreen> mSplitScreenOptional; private final Optional<SplitScreenController> mSplitScreenOptional;
private final Optional<AppPairs> mAppPairsOptional; private final Optional<AppPairs> mAppPairsOptional;
private final FullscreenTaskListener mFullscreenTaskListener; private final FullscreenTaskListener mFullscreenTaskListener;
private final ShellExecutor mMainExecutor; private final ShellExecutor mMainExecutor;
@@ -51,7 +52,7 @@ public class ShellInitImpl {
DragAndDropController dragAndDropController, DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer, ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional, Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairs> appPairsOptional, Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener, FullscreenTaskListener fullscreenTaskListener,
Transitions transitions, Transitions transitions,
@@ -71,7 +72,7 @@ public class ShellInitImpl {
DragAndDropController dragAndDropController, DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer, ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional, Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairs> appPairsOptional, Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener, FullscreenTaskListener fullscreenTaskListener,
Transitions transitions, Transitions transitions,
@@ -97,7 +98,7 @@ public class ShellInitImpl {
mShellTaskOrganizer.registerOrganizer(); mShellTaskOrganizer.registerOrganizer();
mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered); mAppPairsOptional.ifPresent(AppPairs::onOrganizerRegistered);
mSplitScreenOptional.ifPresent(SplitScreen::onOrganizerRegistered); mSplitScreenOptional.ifPresent(SplitScreenController::onOrganizerRegistered);
// Bind the splitscreen impl to the drag drop controller // Bind the splitscreen impl to the drag drop controller
mDragAndDropController.initialize(mSplitScreenOptional); mDragAndDropController.initialize(mSplitScreenOptional);

View File

@@ -53,6 +53,7 @@ import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import java.util.Optional; import java.util.Optional;
@@ -66,7 +67,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
private final Context mContext; private final Context mContext;
private final DisplayController mDisplayController; private final DisplayController mDisplayController;
private SplitScreen mSplitScreen; private SplitScreenController mSplitScreen;
private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>(); private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
@@ -76,7 +77,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange
mDisplayController = displayController; mDisplayController = displayController;
} }
public void initialize(Optional<SplitScreen> splitscreen) { public void initialize(Optional<SplitScreenController> splitscreen) {
mSplitScreen = splitscreen.orElse(null); mSplitScreen = splitscreen.orElse(null);
mDisplayController.addDisplayWindowListener(this); mDisplayController.addDisplayWindowListener(this);
} }

View File

@@ -64,7 +64,9 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayLayout; 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.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
@@ -81,18 +83,18 @@ public class DragAndDropPolicy {
private final Context mContext; private final Context mContext;
private final ActivityTaskManager mActivityTaskManager; private final ActivityTaskManager mActivityTaskManager;
private final Starter mStarter; private final Starter mStarter;
private final SplitScreen mSplitScreen; private final SplitScreenController mSplitScreen;
private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>(); private final ArrayList<DragAndDropPolicy.Target> mTargets = new ArrayList<>();
private DragSession mSession; private DragSession mSession;
public DragAndDropPolicy(Context context, SplitScreen splitScreen) { public DragAndDropPolicy(Context context, SplitScreenController splitScreen) {
this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context)); this(context, ActivityTaskManager.getInstance(), splitScreen, new DefaultStarter(context));
} }
@VisibleForTesting @VisibleForTesting
DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager, DragAndDropPolicy(Context context, ActivityTaskManager activityTaskManager,
SplitScreen splitScreen, Starter starter) { SplitScreenController splitScreen, Starter starter) {
mContext = context; mContext = context;
mActivityTaskManager = activityTaskManager; mActivityTaskManager = activityTaskManager;
mSplitScreen = splitScreen; mSplitScreen = splitScreen;
@@ -200,8 +202,8 @@ public class DragAndDropPolicy {
final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible(); final boolean inSplitScreen = mSplitScreen != null && mSplitScreen.isSplitScreenVisible();
final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT; final boolean leftOrTop = target.type == TYPE_SPLIT_TOP || target.type == TYPE_SPLIT_LEFT;
@SplitScreen.StageType int stage = STAGE_TYPE_UNDEFINED; @StageType int stage = STAGE_TYPE_UNDEFINED;
@SplitScreen.StagePosition int position = STAGE_POSITION_UNDEFINED; @StagePosition int position = STAGE_POSITION_UNDEFINED;
if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) { if (target.type != TYPE_FULLSCREEN && mSplitScreen != null) {
// Update launch options for the split side we are targeting. // Update launch options for the split side we are targeting.
position = leftOrTop ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT; 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 ClipDescription description = data.getDescription();
final Intent dragData = mSession.dragData; 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. * Interface for actually committing the task launches.
*/ */
@VisibleForTesting
public interface Starter { public interface Starter {
default void startClipDescription(ClipDescription description, Intent intent, void startTask(int taskId, @StageType int stage, @StagePosition int position,
@SplitScreen.StageType int stage, @SplitScreen.StagePosition int position) { @Nullable Bundle options);
final boolean isTask = description.hasMimeType(MIMETYPE_APPLICATION_TASK); void startShortcut(String packageName, String shortcutId, @StageType int stage,
final boolean isShortcut = description.hasMimeType(MIMETYPE_APPLICATION_SHORTCUT); @StagePosition int position, @Nullable Bundle options, UserHandle user);
final Bundle opts = intent.hasExtra(EXTRA_ACTIVITY_OPTIONS) void startIntent(PendingIntent intent, @StageType int stage, @StagePosition int position,
? intent.getBundleExtra(EXTRA_ACTIVITY_OPTIONS) : new Bundle(); @Nullable Bundle options);
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 enterSplitScreen(int taskId, boolean leftOrTop); void enterSplitScreen(int taskId, boolean leftOrTop);
void exitSplitScreen(); void exitSplitScreen();
} }

View File

@@ -42,7 +42,7 @@ import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.R; import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.DisplayLayout;
import com.android.wm.shell.protolog.ShellProtoLogGroup; 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; import java.util.ArrayList;
@@ -61,7 +61,7 @@ public class DragLayout extends View {
private boolean mIsShowing; private boolean mIsShowing;
private boolean mHasDropped; private boolean mHasDropped;
public DragLayout(Context context, SplitScreen splitscreen) { public DragLayout(Context context, SplitScreenController splitscreen) {
super(context); super(context);
mPolicy = new DragAndDropPolicy(context, splitscreen); mPolicy = new DragAndDropPolicy(context, splitscreen);
mDisplayMargin = context.getResources().getDimensionPixelSize( mDisplayMargin = context.getResources().getDimensionPixelSize(

View File

@@ -33,6 +33,7 @@ import java.io.PrintWriter;
/** /**
* Interface to engage split-screen feature. * Interface to engage split-screen feature.
* TODO: Figure out which of these are actually needed outside of the Shell
*/ */
@ExternalThread @ExternalThread
public interface SplitScreen extends DragAndDropPolicy.Starter { public interface SplitScreen extends DragAndDropPolicy.Starter {
@@ -102,18 +103,11 @@ public interface SplitScreen extends DragAndDropPolicy.Starter {
void setSideStagePosition(@StagePosition int sideStagePosition); void setSideStagePosition(@StagePosition int sideStagePosition);
/** Hides the side-stage if it is currently visible. */ /** Hides the side-stage if it is currently visible. */
void setSideStageVisibility(boolean 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. */ /** Removes the split-screen stages. */
void exitSplitScreen(); void exitSplitScreen();
/** Gets the stage bounds. */ /** Gets the stage bounds. */
void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds); 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 registerSplitScreenListener(SplitScreenListener listener);
void unregisterSplitScreenListener(SplitScreenListener listener); void unregisterSplitScreenListener(SplitScreenListener listener);

View File

@@ -18,6 +18,13 @@ package com.android.wm.shell.splitscreen;
import static android.view.Display.DEFAULT_DISPLAY; 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.ActivityManager;
import android.app.ActivityTaskManager; import android.app.ActivityTaskManager;
import android.app.PendingIntent; import android.app.PendingIntent;
@@ -35,7 +42,9 @@ import androidx.annotation.Nullable;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer; 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.common.SyncTransactionQueue;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -44,25 +53,33 @@ import java.io.PrintWriter;
* {@link SplitScreen}. * {@link SplitScreen}.
* @see StageCoordinator * @see StageCoordinator
*/ */
public class SplitScreenController implements SplitScreen { public class SplitScreenController implements DragAndDropPolicy.Starter {
private static final String TAG = SplitScreenController.class.getSimpleName(); private static final String TAG = SplitScreenController.class.getSimpleName();
private final ShellTaskOrganizer mTaskOrganizer; private final ShellTaskOrganizer mTaskOrganizer;
private final SyncTransactionQueue mSyncQueue; private final SyncTransactionQueue mSyncQueue;
private final Context mContext; private final Context mContext;
private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer; private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
private final ShellExecutor mMainExecutor;
private final SplitScreenImpl mImpl = new SplitScreenImpl();
private StageCoordinator mStageCoordinator; private StageCoordinator mStageCoordinator;
public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer,
SyncTransactionQueue syncQueue, Context context, SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer) { RootTaskDisplayAreaOrganizer rootTDAOrganizer,
ShellExecutor mainExecutor) {
mTaskOrganizer = shellTaskOrganizer; mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue; mSyncQueue = syncQueue;
mContext = context; mContext = context;
mRootTDAOrganizer = rootTDAOrganizer; mRootTDAOrganizer = rootTDAOrganizer;
mMainExecutor = mainExecutor;
}
public SplitScreen asSplitScreen() {
return mImpl;
} }
@Override
public void onOrganizerRegistered() { public void onOrganizerRegistered() {
if (mStageCoordinator == null) { if (mStageCoordinator == null) {
// TODO: Multi-display // TODO: Multi-display
@@ -71,13 +88,11 @@ public class SplitScreenController implements SplitScreen {
} }
} }
@Override
public boolean isSplitScreenVisible() { public boolean isSplitScreenVisible() {
return mStageCoordinator.isSplitScreenVisible(); return mStageCoordinator.isSplitScreenVisible();
} }
@Override public boolean moveToSideStage(int taskId, @SplitScreen.StagePosition int sideStagePosition) {
public boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition) {
final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId); final ActivityManager.RunningTaskInfo task = mTaskOrganizer.getRunningTaskInfo(taskId);
if (task == null) { if (task == null) {
throw new IllegalArgumentException("Unknown taskId" + taskId); throw new IllegalArgumentException("Unknown taskId" + taskId);
@@ -85,50 +100,46 @@ public class SplitScreenController implements SplitScreen {
return moveToSideStage(task, sideStagePosition); return moveToSideStage(task, sideStagePosition);
} }
@Override
public boolean moveToSideStage(ActivityManager.RunningTaskInfo task, public boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@StagePosition int sideStagePosition) { @SplitScreen.StagePosition int sideStagePosition) {
return mStageCoordinator.moveToSideStage(task, sideStagePosition); return mStageCoordinator.moveToSideStage(task, sideStagePosition);
} }
@Override
public boolean removeFromSideStage(int taskId) { public boolean removeFromSideStage(int taskId) {
return mStageCoordinator.removeFromSideStage(taskId); return mStageCoordinator.removeFromSideStage(taskId);
} }
@Override public void setSideStagePosition(@SplitScreen.StagePosition int sideStagePosition) {
public void setSideStagePosition(@StagePosition int sideStagePosition) {
mStageCoordinator.setSideStagePosition(sideStagePosition); mStageCoordinator.setSideStagePosition(sideStagePosition);
} }
@Override
public void setSideStageVisibility(boolean visible) { public void setSideStageVisibility(boolean visible) {
mStageCoordinator.setSideStageVisibility(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() { public void exitSplitScreen() {
mStageCoordinator.exitSplitScreen(); mStageCoordinator.exitSplitScreen();
} }
@Override
public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { public void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) {
mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds); mStageCoordinator.getStageBounds(outTopOrLeftBounds, outBottomOrRightBounds);
} }
@Override public void registerSplitScreenListener(SplitScreen.SplitScreenListener listener) {
public void registerSplitScreenListener(SplitScreenListener listener) {
mStageCoordinator.registerSplitScreenListener(listener); mStageCoordinator.registerSplitScreenListener(listener);
} }
@Override public void unregisterSplitScreenListener(SplitScreen.SplitScreenListener listener) {
public void unregisterSplitScreenListener(SplitScreenListener listener) {
mStageCoordinator.unregisterSplitScreenListener(listener); mStageCoordinator.unregisterSplitScreenListener(listener);
} }
@Override public void startTask(int taskId, @SplitScreen.StageType int stage,
public void startTask(int taskId, @SplitScreen.StagePosition int position, @Nullable Bundle options) {
@StageType int stage, @StagePosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options); options = resolveStartStage(stage, position, options);
try { try {
@@ -138,9 +149,9 @@ public class SplitScreenController implements SplitScreen {
} }
} }
@Override public void startShortcut(String packageName, String shortcutId,
public void startShortcut(String packageName, String shortcutId, @StageType int stage, @SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
@StagePosition int position, @Nullable Bundle options, UserHandle user) { @Nullable Bundle options, UserHandle user) {
options = resolveStartStage(stage, position, options); options = resolveStartStage(stage, position, options);
try { try {
@@ -153,9 +164,8 @@ public class SplitScreenController implements SplitScreen {
} }
} }
@Override public void startIntent(PendingIntent intent, @SplitScreen.StageType int stage,
public void startIntent(PendingIntent intent, @SplitScreen.StagePosition int position, @Nullable Bundle options) {
@StageType int stage, @StagePosition int position, @Nullable Bundle options) {
options = resolveStartStage(stage, position, options); options = resolveStartStage(stage, position, options);
try { try {
@@ -165,8 +175,8 @@ public class SplitScreenController implements SplitScreen {
} }
} }
private Bundle resolveStartStage(@StageType int stage, @StagePosition int position, private Bundle resolveStartStage(@SplitScreen.StageType int stage,
@Nullable Bundle options) { @SplitScreen.StagePosition int position, @Nullable Bundle options) {
switch (stage) { switch (stage) {
case STAGE_TYPE_UNDEFINED: { case STAGE_TYPE_UNDEFINED: {
// Use the stage of the specified position is valid. // Use the stage of the specified position is valid.
@@ -216,7 +226,6 @@ public class SplitScreenController implements SplitScreen {
return options; return options;
} }
@Override
public void dump(@NonNull PrintWriter pw, String prefix) { public void dump(@NonNull PrintWriter pw, String prefix) {
pw.println(prefix + TAG); pw.println(prefix + TAG);
if (mStageCoordinator != null) { 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);
});
}
}
} }

View File

@@ -377,12 +377,10 @@ public class StartingSurfaceDrawer {
final int taskId = startingWindowInfo.taskInfo.taskId; final int taskId = startingWindowInfo.taskInfo.taskId;
final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken, final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */); snapshot, mMainExecutor, () -> removeWindowSynced(taskId) /* clearWindow */);
mMainExecutor.execute(() -> { mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT); final StartingWindowRecord tView =
final StartingWindowRecord tView = new StartingWindowRecord(null/* decorView */, surface);
new StartingWindowRecord(null/* decorView */, surface); mStartingWindowRecords.put(taskId, tView);
mStartingWindowRecords.put(taskId, tView);
});
} }
/** /**
@@ -392,42 +390,40 @@ public class StartingSurfaceDrawer {
if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) { if (DEBUG_SPLASH_SCREEN || DEBUG_TASK_SNAPSHOT) {
Slog.d(TAG, "Task start finish, remove starting surface for task " + taskId); 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, protected void postAddWindow(int taskId, IBinder appToken,
View view, WindowManager wm, WindowManager.LayoutParams params) { View view, WindowManager wm, WindowManager.LayoutParams params) {
mMainExecutor.execute(() -> { boolean shouldSaveView = true;
boolean shouldSaveView = true; try {
try { wm.addView(view, params);
wm.addView(view, params); } catch (WindowManager.BadTokenException e) {
} catch (WindowManager.BadTokenException e) { // ignore
// ignore Slog.w(TAG, appToken + " already running, starting window not displayed. "
Slog.w(TAG, appToken + " already running, starting window not displayed. " + e.getMessage());
+ 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; 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) { if (shouldSaveView) {
removeWindowSynced(taskId); removeWindowSynced(taskId);
mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT); mMainExecutor.executeDelayed(() -> removeWindowSynced(taskId), REMOVE_WHEN_TIMEOUT);
final StartingWindowRecord tView = final StartingWindowRecord tView =
new StartingWindowRecord(view, null /* TaskSnapshotWindow */); new StartingWindowRecord(view, null /* TaskSnapshotWindow */);
mStartingWindowRecords.put(taskId, tView); mStartingWindowRecords.put(taskId, tView);
} }
});
} }
protected void removeWindowSynced(int taskId) { protected void removeWindowSynced(int taskId) {
@@ -445,7 +441,7 @@ public class StartingSurfaceDrawer {
if (DEBUG_TASK_SNAPSHOT) { if (DEBUG_TASK_SNAPSHOT) {
Slog.v(TAG, "Removing task snapshot window for " + taskId); Slog.v(TAG, "Removing task snapshot window for " + taskId);
} }
record.mTaskSnapshotWindow.remove(mMainExecutor); record.mTaskSnapshotWindow.remove();
} }
mStartingWindowRecords.remove(taskId); mStartingWindowRecords.remove(taskId);
} }

View File

@@ -82,6 +82,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DecorView; import com.android.internal.policy.DecorView;
import com.android.internal.view.BaseIWindow; import com.android.internal.view.BaseIWindow;
import com.android.wm.shell.common.ShellExecutor; 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. * This class represents a starting window that shows a snapshot.
@@ -121,6 +122,7 @@ public class TaskSnapshotWindow {
private final Window mWindow; private final Window mWindow;
private final Surface mSurface; private final Surface mSurface;
private final Runnable mClearWindowHandler; private final Runnable mClearWindowHandler;
private final ShellExecutor mMainExecutor;
private SurfaceControl mSurfaceControl; private SurfaceControl mSurfaceControl;
private SurfaceControl mChildSurfaceControl; private SurfaceControl mChildSurfaceControl;
private final IWindowSession mSession; private final IWindowSession mSession;
@@ -213,7 +215,7 @@ public class TaskSnapshotWindow {
final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow( final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance, surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
windowFlags, windowPrivateFlags, taskBounds, orientation, activityType, windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
topWindowInsetsState, clearWindowHandler); topWindowInsetsState, clearWindowHandler, mainExecutor);
final Window window = snapshotSurface.mWindow; final Window window = snapshotSurface.mWindow;
final InsetsState mTmpInsetsState = new InsetsState(); final InsetsState mTmpInsetsState = new InsetsState();
@@ -229,7 +231,7 @@ public class TaskSnapshotWindow {
} catch (RemoteException e) { } catch (RemoteException e) {
snapshotSurface.clearWindowSynced(); snapshotSurface.clearWindowSynced();
} }
window.setOuter(snapshotSurface, mainExecutor); window.setOuter(snapshotSurface);
try { try {
session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1, session.relayout(window, layoutParams, -1, -1, View.VISIBLE, 0, -1,
tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState, tmpFrames, tmpMergedConfiguration, surfaceControl, mTmpInsetsState,
@@ -249,7 +251,8 @@ public class TaskSnapshotWindow {
TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription, TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds, int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
int currentOrientation, int activityType, InsetsState topWindowInsetsState, int currentOrientation, int activityType, InsetsState topWindowInsetsState,
Runnable clearWindowHandler) { Runnable clearWindowHandler, ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
mSurface = new Surface(); mSurface = new Surface();
mSession = WindowManagerGlobal.getWindowSession(); mSession = WindowManagerGlobal.getWindowSession();
mWindow = new Window(); mWindow = new Window();
@@ -286,28 +289,26 @@ public class TaskSnapshotWindow {
mSystemBarBackgroundPainter.drawNavigationBarBackground(c); mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
} }
void remove(ShellExecutor mainExecutor) { void remove() {
final long now = SystemClock.uptimeMillis(); final long now = SystemClock.uptimeMillis();
if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS
// Show the latest content as soon as possible for unlocking to home. // Show the latest content as soon as possible for unlocking to home.
&& mActivityType != ACTIVITY_TYPE_HOME) { && mActivityType != ACTIVITY_TYPE_HOME) {
final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now; final long delayTime = mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS - now;
mainExecutor.executeDelayed(() -> remove(mainExecutor), delayTime); mMainExecutor.executeDelayed(() -> remove(), delayTime);
if (DEBUG) { if (DEBUG) {
Slog.d(TAG, "Defer removing snapshot surface in " + delayTime); Slog.d(TAG, "Defer removing snapshot surface in " + delayTime);
} }
return; return;
} }
mainExecutor.execute(() -> { try {
try { if (DEBUG) {
if (DEBUG) { Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
Slog.d(TAG, "Removing snapshot surface, mHasDrawn: " + mHasDrawn);
}
mSession.remove(mWindow);
} catch (RemoteException e) {
// nothing
} }
}); mSession.remove(mWindow);
} catch (RemoteException e) {
// nothing
}
} }
/** /**
@@ -497,13 +498,12 @@ public class TaskSnapshotWindow {
} }
} }
@ExternalThread
static class Window extends BaseIWindow { static class Window extends BaseIWindow {
private TaskSnapshotWindow mOuter; private TaskSnapshotWindow mOuter;
private ShellExecutor mMainExecutor;
public void setOuter(TaskSnapshotWindow outer, ShellExecutor mainExecutor) { public void setOuter(TaskSnapshotWindow outer) {
mOuter = outer; mOuter = outer;
mMainExecutor = mainExecutor;
} }
@Override @Override
@@ -511,22 +511,20 @@ public class TaskSnapshotWindow {
MergedConfiguration mergedConfiguration, boolean forceLayout, MergedConfiguration mergedConfiguration, boolean forceLayout,
boolean alwaysConsumeSystemBars, int displayId) { boolean alwaysConsumeSystemBars, int displayId) {
if (mOuter != null) { if (mOuter != null) {
if (mergedConfiguration != null mOuter.mMainExecutor.execute(() -> {
&& mOuter.mOrientationOnCreation if (mergedConfiguration != null
!= mergedConfiguration.getMergedConfiguration().orientation) { && mOuter.mOrientationOnCreation
// The orientation of the screen is changing. We better remove the snapshot ASAP != mergedConfiguration.getMergedConfiguration().orientation) {
// as we are going to wait on the new window in any case to unfreeze the screen, // The orientation of the screen is changing. We better remove the snapshot
// and the starting window is not needed anymore. // ASAP as we are going to wait on the new window in any case to unfreeze
mMainExecutor.execute(() -> { // the screen, and the starting window is not needed anymore.
mOuter.clearWindowSynced(); mOuter.clearWindowSynced();
}); } else if (reportDraw) {
} else if (reportDraw) {
mMainExecutor.execute(() -> {
if (mOuter.mHasDrawn) { if (mOuter.mHasDrawn) {
mOuter.reportDrawn(); mOuter.reportDrawn();
} }
}); }
} });
} }
} }
} }

View File

@@ -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);
}

View File

@@ -67,6 +67,7 @@ public class Transitions {
private final ShellExecutor mAnimExecutor; private final ShellExecutor mAnimExecutor;
private final TransitionPlayerImpl mPlayerImpl; private final TransitionPlayerImpl mPlayerImpl;
private final RemoteTransitionHandler mRemoteTransitionHandler; private final RemoteTransitionHandler mRemoteTransitionHandler;
private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */ /** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>(); 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 */ /** Keeps track of currently tracked transitions and all the animations associated with each */
private final ArrayMap<IBinder, ActiveTransition> mActiveTransitions = new ArrayMap<>(); 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, public Transitions(@NonNull WindowOrganizer organizer, @NonNull TransactionPool pool,
@NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) { @NonNull ShellExecutor mainExecutor, @NonNull ShellExecutor animExecutor) {
mOrganizer = organizer; mOrganizer = organizer;
@@ -101,8 +106,20 @@ public class Transitions {
/** Create an empty/non-registering transitions object for system-ui tests. */ /** Create an empty/non-registering transitions object for system-ui tests. */
@VisibleForTesting @VisibleForTesting
public static Transitions createEmptyForTesting() { public static RemoteTransitions createEmptyForTesting() {
return new Transitions(); 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 */ /** 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 */ /** Register a remote transition to be used when `filter` matches an incoming transition */
@ExternalThread
public void registerRemote(@NonNull TransitionFilter filter, public void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition) { @NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> mRemoteTransitionHandler.addFiltered(filter, remoteTransition)); mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
} }
/** Unregisters a remote transition and all associated filters */ /** Unregisters a remote transition and all associated filters */
@ExternalThread
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) { 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 */ /** @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)); 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);
});
}
}
} }

View File

@@ -44,6 +44,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset; import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import android.app.ActivityManager; 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.common.DisplayLayout;
import com.android.wm.shell.draganddrop.DragAndDropPolicy.Target; 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.Before;
import org.junit.Test; import org.junit.Test;
@@ -92,7 +93,7 @@ public class DragAndDropPolicyTest {
// Both the split-screen and start interface. // Both the split-screen and start interface.
@Mock @Mock
private SplitScreen mSplitScreenStarter; private SplitScreenController mSplitScreenStarter;
private DisplayLayout mLandscapeDisplayLayout; private DisplayLayout mLandscapeDisplayLayout;
private DisplayLayout mPortraitDisplayLayout; private DisplayLayout mPortraitDisplayLayout;
@@ -127,8 +128,8 @@ public class DragAndDropPolicyTest {
mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false); mPortraitDisplayLayout = new DisplayLayout(info2, res, false, false);
mInsets = Insets.of(0, 0, 0, 0); mInsets = Insets.of(0, 0, 0, 0);
mPolicy = new DragAndDropPolicy( mPolicy = spy(new DragAndDropPolicy(
mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter); mContext, mActivityTaskManager, mSplitScreenStarter, mSplitScreenStarter));
mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); mActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY); mNonResizeableActivityClipData = createClipData(MIMETYPE_APPLICATION_ACTIVITY);
setClipDataResizeable(mNonResizeableActivityClipData, false); setClipDataResizeable(mNonResizeableActivityClipData, false);
@@ -204,8 +205,8 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN); mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
} }
@Test @Test
@@ -216,13 +217,13 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter); reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
} }
@Test @Test
@@ -233,13 +234,13 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter); reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
} }
@Test @Test
@@ -250,8 +251,8 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
} }
@Test @Test
@@ -262,8 +263,8 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
} }
@Test @Test
@@ -275,14 +276,14 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT); mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter); reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
} }
@Test @Test
@@ -294,14 +295,14 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM); mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED)); eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter); reset(mSplitScreenStarter);
// TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs // TODO(b/169894807): Just verify starting for the non-docked task until we have app pairs
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData); mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
verify(mSplitScreenStarter).startClipDescription(any(), any(), verify(mSplitScreenStarter).startIntent(any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT)); eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
} }
@Test @Test

View File

@@ -47,6 +47,7 @@ import android.window.TaskSnapshot;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.wm.shell.TestShellExecutor;
import com.android.wm.shell.startingsurface.TaskSnapshotWindow; import com.android.wm.shell.startingsurface.TaskSnapshotWindow;
import org.junit.Test; import org.junit.Test;
@@ -83,7 +84,7 @@ public class TaskSnapshotWindowTest {
createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */, 0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(), taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState(),
null /* clearWindow */); null /* clearWindow */, new TestShellExecutor());
} }
private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize, private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,

View File

@@ -33,7 +33,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen; 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; import java.util.Optional;
@@ -86,7 +86,7 @@ public interface SysUIComponent {
Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump); Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
@BindsInstance @BindsInstance
Builder setTransitions(Transitions t); Builder setTransitions(RemoteTransitions t);
SysUIComponent build(); SysUIComponent build();
} }

View File

@@ -27,7 +27,7 @@ import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.onehanded.OneHanded; import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen; 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; import java.util.Optional;
@@ -55,16 +55,12 @@ public interface WMComponent {
getShellInit().init(); getShellInit().init();
} }
// Gets the Shell init instance
@WMSingleton @WMSingleton
ShellInit getShellInit(); ShellInit getShellInit();
// Gets the Shell dump instance
@WMSingleton @WMSingleton
Optional<ShellCommandHandler> getShellCommandHandler(); 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 @WMSingleton
Optional<OneHanded> getOneHanded(); Optional<OneHanded> getOneHanded();
@@ -89,7 +85,6 @@ public interface WMComponent {
@WMSingleton @WMSingleton
Optional<TaskViewFactory> getTaskViewFactory(); Optional<TaskViewFactory> getTaskViewFactory();
/** Gets transitions */
@WMSingleton @WMSingleton
Transitions getTransitions(); RemoteTransitions getTransitions();
} }

View File

@@ -101,7 +101,7 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipAnimationController; import com.android.wm.shell.pip.PipAnimationController;
import com.android.wm.shell.splitscreen.SplitScreen; 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.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
@@ -149,7 +149,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final ScreenshotHelper mScreenshotHelper; private final ScreenshotHelper mScreenshotHelper;
private final Optional<OneHanded> mOneHandedOptional; private final Optional<OneHanded> mOneHandedOptional;
private final CommandQueue mCommandQueue; private final CommandQueue mCommandQueue;
private final Transitions mShellTransitions; private final RemoteTransitions mShellTransitions;
private Region mActiveNavBarRegion; private Region mActiveNavBarRegion;
@@ -799,7 +799,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
Optional<Lazy<StatusBar>> statusBarOptionalLazy, Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional, Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher, BroadcastDispatcher broadcastDispatcher,
Transitions shellTransitions) { RemoteTransitions shellTransitions) {
super(broadcastDispatcher); super(broadcastDispatcher);
mContext = context; mContext = context;
mPipOptional = pipOptional; mPipOptional = pipOptional;

View File

@@ -75,6 +75,7 @@ import com.android.wm.shell.sizecompatui.SizeCompatUI;
import com.android.wm.shell.sizecompatui.SizeCompatUIController; import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.splitscreen.SplitScreen; import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController; import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.transition.Transitions;
import java.util.Optional; import java.util.Optional;
@@ -179,7 +180,7 @@ public abstract class WMShellBaseModule {
DragAndDropController dragAndDropController, DragAndDropController dragAndDropController,
ShellTaskOrganizer shellTaskOrganizer, ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional, Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairs> appPairsOptional, Optional<AppPairs> appPairsOptional,
FullscreenTaskListener fullscreenTaskListener, FullscreenTaskListener fullscreenTaskListener,
Transitions transitions, Transitions transitions,
@@ -204,7 +205,7 @@ public abstract class WMShellBaseModule {
static Optional<ShellCommandHandler> provideShellCommandHandler( static Optional<ShellCommandHandler> provideShellCommandHandler(
ShellTaskOrganizer shellTaskOrganizer, ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<LegacySplitScreen> legacySplitScreenOptional,
Optional<SplitScreen> splitScreenOptional, Optional<SplitScreenController> splitScreenOptional,
Optional<Pip> pipOptional, Optional<Pip> pipOptional,
Optional<OneHanded> oneHandedOptional, Optional<OneHanded> oneHandedOptional,
Optional<HideDisplayCutout> hideDisplayCutout, Optional<HideDisplayCutout> hideDisplayCutout,
@@ -319,12 +320,21 @@ public abstract class WMShellBaseModule {
@WMSingleton @WMSingleton
@Provides @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, SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) { RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@ShellMainThread ShellExecutor mainExecutor) {
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) { if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context, return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
rootTaskDisplayAreaOrganizer)); rootTaskDisplayAreaOrganizer, mainExecutor));
} else { } else {
return Optional.empty(); return Optional.empty();
} }
@@ -386,6 +396,12 @@ public abstract class WMShellBaseModule {
return new FullscreenTaskListener(syncQueue); return new FullscreenTaskListener(syncQueue);
} }
@WMSingleton
@Provides
static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
return Transitions.asRemoteTransitions(transitions);
}
@WMSingleton @WMSingleton
@Provides @Provides
static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool, static Transitions provideTransitions(ShellTaskOrganizer organizer, TransactionPool pool,

View File

@@ -43,7 +43,7 @@ import com.android.systemui.statusbar.phone.StatusBar;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen; 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.Before;
import org.junit.Test; 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 Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
@Mock private PackageManager mPackageManager; @Mock private PackageManager mPackageManager;
@Mock private SysUiState mMockSysUiState; @Mock private SysUiState mMockSysUiState;
@Mock private Transitions mMockTransitions; @Mock private RemoteTransitions mMockTransitions;
@Before @Before
public void setUp() throws RemoteException { public void setUp() throws RemoteException {