2/ Add mechanism to expose other features directly

- Expose interfaces for splitscreen, one handed, shell transitions,
  starting window
- Make the shell code only reference the starting window controller and
  not the exported interface

Bug: 180074017
Test: atest WMShellUnitTests
Test: Verify Pip calls from Launcher work
Change-Id: I49a5a0419996754e5e154df7af1e475268035a5a
This commit is contained in:
Winson Chung
2021-02-16 14:27:46 -08:00
parent 2b52dceafc
commit 8e76243e57
25 changed files with 719 additions and 569 deletions

View File

@@ -26,7 +26,7 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.legacysplitscreen.LegacySplitScreenController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.startingsurface.StartingWindowController;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -47,7 +47,7 @@ public class ShellInitImpl {
private final FullscreenTaskListener mFullscreenTaskListener;
private final ShellExecutor mMainExecutor;
private final Transitions mTransitions;
private final Optional<StartingSurface> mStartingSurfaceOptional;
private final StartingWindowController mStartingWindow;
private final InitImpl mImpl = new InitImpl();
@@ -57,10 +57,10 @@ public class ShellInitImpl {
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
Optional<StartingSurface> startingSurfaceOptional,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
StartingWindowController startingWindow,
ShellExecutor mainExecutor) {
mDisplayImeController = displayImeController;
mDragAndDropController = dragAndDropController;
@@ -72,7 +72,7 @@ public class ShellInitImpl {
mPipTouchHandlerOptional = pipTouchHandlerOptional;
mTransitions = transitions;
mMainExecutor = mainExecutor;
mStartingSurfaceOptional = startingSurfaceOptional;
mStartingWindow = startingWindow;
}
public ShellInit asShellInit() {
@@ -83,10 +83,10 @@ public class ShellInitImpl {
// Start listening for display changes
mDisplayImeController.startMonitorDisplays();
// Setup the shell organizer
mShellTaskOrganizer.addListenerForType(
mFullscreenTaskListener, TASK_LISTENER_TYPE_FULLSCREEN);
mStartingSurfaceOptional.ifPresent(mShellTaskOrganizer::initStartingSurface);
// Register the shell organizer
mShellTaskOrganizer.initStartingWindow(mStartingWindow);
mShellTaskOrganizer.registerOrganizer();
mAppPairsOptional.ifPresent(AppPairsController::onOrganizerRegistered);

View File

@@ -48,7 +48,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.sizecompatui.SizeCompatUIController;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.startingsurface.StartingWindowController;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -133,7 +133,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
private final ArraySet<LocusIdListener> mLocusIdListeners = new ArraySet<>();
private final Object mLock = new Object();
private StartingSurface mStartingSurface;
private StartingWindowController mStartingWindow;
/**
* In charge of showing size compat UI. Can be {@code null} if device doesn't support size
@@ -184,8 +184,8 @@ public class ShellTaskOrganizer extends TaskOrganizer {
/**
* @hide
*/
public void initStartingSurface(StartingSurface startingSurface) {
mStartingSurface = startingSurface;
public void initStartingWindow(StartingWindowController startingWindow) {
mStartingWindow = startingWindow;
}
/**
@@ -302,23 +302,23 @@ public class ShellTaskOrganizer extends TaskOrganizer {
@Override
public void addStartingWindow(StartingWindowInfo info, IBinder appToken) {
if (mStartingSurface != null) {
mStartingSurface.addStartingWindow(info, appToken);
if (mStartingWindow != null) {
mStartingWindow.addStartingWindow(info, appToken);
}
}
@Override
public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation) {
if (mStartingSurface != null) {
mStartingSurface.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
if (mStartingWindow != null) {
mStartingWindow.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
}
}
@Override
public void copySplashScreenView(int taskId) {
if (mStartingSurface != null) {
mStartingSurface.copySplashScreenView(taskId);
if (mStartingWindow != null) {
mStartingWindow.copySplashScreenView(taskId);
}
}

View File

@@ -235,7 +235,7 @@ public class DragAndDropPolicy {
mStarter.startShortcut(packageName, id, stage, position, opts, user);
} else {
mStarter.startIntent(intent.getParcelableExtra(EXTRA_PENDING_INTENT),
mContext, null, stage, position, opts);
null, stage, position, opts);
}
}
@@ -295,7 +295,7 @@ public class DragAndDropPolicy {
@Nullable Bundle options);
void startShortcut(String packageName, String shortcutId, @StageType int stage,
@StagePosition int position, @Nullable Bundle options, UserHandle user);
void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
void startIntent(PendingIntent intent, Intent fillInIntent,
@StageType int stage, @StagePosition int position,
@Nullable Bundle options);
void enterSplitScreen(int taskId, boolean leftOrTop);
@@ -337,9 +337,8 @@ public class DragAndDropPolicy {
}
@Override
public void startIntent(PendingIntent intent, Context context,
@Nullable Intent fillInIntent, int stage, int position,
@Nullable Bundle options) {
public void startIntent(PendingIntent intent, @Nullable Intent fillInIntent, int stage,
int position, @Nullable Bundle options) {
try {
intent.send(mContext, 0, fillInIntent, null, null, null, options);
} catch (PendingIntent.CanceledException e) {

View File

@@ -0,0 +1,33 @@
/*
* 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.onehanded;
/**
* Interface that is exposed to remote callers to manipulate the OneHanded feature.
*/
interface IOneHanded {
/**
* Enters one handed mode.
*/
oneway void startOneHanded() = 1;
/**
* Exits one handed mode.
*/
oneway void stopOneHanded() = 2;
}

View File

@@ -26,6 +26,14 @@ import com.android.wm.shell.onehanded.OneHandedGestureHandler.OneHandedGestureEv
*/
@ExternalThread
public interface OneHanded {
/**
* Returns a binder that can be passed to an external process to manipulate OneHanded.
*/
default IOneHanded createExternalInterface() {
return null;
}
/**
* Return one handed settings enabled or not.
*/

View File

@@ -18,6 +18,10 @@ package com.android.wm.shell.onehanded;
import static android.os.UserHandle.USER_CURRENT;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import android.Manifest;
import android.annotation.BinderThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.om.IOverlayManager;
@@ -43,6 +47,8 @@ import com.android.internal.logging.UiEventLogger;
import com.android.wm.shell.R;
import com.android.wm.shell.common.DisplayChangeController;
import com.android.wm.shell.common.DisplayController;
import com.android.wm.shell.common.ExecutorUtils;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -54,7 +60,7 @@ import java.io.PrintWriter;
/**
* Manages and manipulates the one handed states, transitions, and gesture for phones.
*/
public class OneHandedController {
public class OneHandedController implements RemoteCallable<OneHandedController> {
private static final String TAG = "OneHandedController";
private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE =
@@ -239,6 +245,16 @@ public class OneHandedController {
return mImpl;
}
@Override
public Context getContext() {
return mContext;
}
@Override
public ShellExecutor getRemoteCallExecutor() {
return mMainExecutor;
}
/**
* Set one handed enabled or disabled when user update settings
*/
@@ -567,8 +583,22 @@ public class OneHandedController {
}
}
/**
* The interface for calls from outside the Shell, within the host process.
*/
@ExternalThread
private class OneHandedImpl implements OneHanded {
private IOneHandedImpl mIOneHanded;
@Override
public IOneHanded createExternalInterface() {
if (mIOneHanded != null) {
mIOneHanded.invalidate();
}
mIOneHanded = new IOneHandedImpl(OneHandedController.this);
return mIOneHanded;
}
@Override
public boolean isOneHandedEnabled() {
// This is volatile so return directly
@@ -637,4 +667,39 @@ public class OneHandedController {
});
}
}
/**
* The interface for calls from outside the host process.
*/
@BinderThread
private static class IOneHandedImpl extends IOneHanded.Stub {
private OneHandedController mController;
IOneHandedImpl(OneHandedController controller) {
mController = controller;
}
/**
* Invalidates this instance, preventing future calls from updating the controller.
*/
void invalidate() {
mController = null;
}
@Override
public void startOneHanded() {
executeRemoteCallWithTaskPermission(mController, "startOneHanded",
(controller) -> {
controller.startOneHanded();
});
}
@Override
public void stopOneHanded() {
executeRemoteCallWithTaskPermission(mController, "stopOneHanded",
(controller) -> {
controller.stopOneHanded();
});
}
}
}

View File

@@ -0,0 +1,77 @@
/*
* 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.splitscreen;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
/**
* Interface that is exposed to remote callers to manipulate the splitscreen feature.
*/
interface ISplitScreen {
/**
* Registers a split screen listener.
*/
oneway void registerSplitScreenListener(in ISplitScreenListener listener) = 1;
/**
* Unregisters a split screen listener.
*/
oneway void unregisterSplitScreenListener(in ISplitScreenListener listener) = 2;
/**
* Hides the side-stage if it is currently visible.
*/
oneway void setSideStageVisibility(boolean visible) = 3;
/**
* Removes a task from the side stage.
*/
oneway void removeFromSideStage(int taskId) = 4;
/**
* Removes the split-screen stages.
*/
oneway void exitSplitScreen() = 5;
/**
* @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible.
*/
oneway void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 6;
/**
* Starts a task in a stage.
*/
oneway void startTask(int taskId, int stage, int position, in Bundle options) = 7;
/**
* Starts a shortcut in a stage.
*/
oneway void startShortcut(String packageName, String shortcutId, int stage, int position,
in Bundle options, in UserHandle user) = 8;
/**
* Starts an activity in a stage.
*/
oneway void startIntent(in PendingIntent intent, in Intent fillInIntent, int stage,
int position, in Bundle options) = 9;
}

View File

@@ -14,12 +14,20 @@
* limitations under the License.
*/
package com.android.systemui.shared.recents;
package com.android.wm.shell.splitscreen;
/**
* Listener interface that Launcher attaches to SystemUI to get split-screen callbacks.
*/
oneway interface ISplitScreenListener {
/**
* Called when the stage position changes.
*/
void onStagePositionChanged(int stage, int position);
/**
* Called when a task changes stages.
*/
void onTaskStageChanged(int taskId, int stage, boolean visible);
}
}

View File

@@ -35,7 +35,7 @@ import com.android.wm.shell.draganddrop.DragAndDropPolicy;
* TODO: Figure out which of these are actually needed outside of the Shell
*/
@ExternalThread
public interface SplitScreen extends DragAndDropPolicy.Starter {
public interface SplitScreen {
/**
* Stage position isn't specified normally meaning to use what ever it is currently set to.
*/
@@ -89,35 +89,10 @@ public interface SplitScreen extends DragAndDropPolicy.Starter {
void onTaskStageChanged(int taskId, @StageType int stage, boolean visible);
}
/** @return {@code true} if split-screen is currently visible. */
boolean isSplitScreenVisible();
/** Moves a task in the side-stage of split-screen. */
boolean moveToSideStage(int taskId, @StagePosition int sideStagePosition);
/** Moves a task in the side-stage of split-screen. */
boolean moveToSideStage(ActivityManager.RunningTaskInfo task,
@StagePosition int sideStagePosition);
/** Removes a task from the side-stage of split-screen. */
boolean removeFromSideStage(int taskId);
/** Sets the position of the side-stage. */
void setSideStagePosition(@StagePosition int sideStagePosition);
/** Hides the side-stage if it is currently visible. */
void setSideStageVisibility(boolean visible);
/** Removes the split-screen stages. */
void exitSplitScreen();
/** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
void exitSplitScreenOnHide(boolean exitSplitScreenOnHide);
/** Gets the stage bounds. */
void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds);
void registerSplitScreenListener(SplitScreenListener listener);
void unregisterSplitScreenListener(SplitScreenListener listener);
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, Context context,
@Nullable Intent fillInIntent, @StageType int stage,
@StagePosition int position, @Nullable Bundle options);
/**
* Returns a binder that can be passed to an external process to manipulate SplitScreen.
*/
default ISplitScreen createExternalInterface() {
return null;
}
}

View File

@@ -18,6 +18,7 @@ package com.android.wm.shell.splitscreen;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
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;
@@ -34,19 +35,24 @@ import android.content.Intent;
import android.content.pm.LauncherApps;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.annotations.ExternalThread;
import com.android.wm.shell.draganddrop.DragAndDropPolicy;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import java.io.PrintWriter;
@@ -55,7 +61,8 @@ import java.io.PrintWriter;
* {@link SplitScreen}.
* @see StageCoordinator
*/
public class SplitScreenController implements DragAndDropPolicy.Starter {
public class SplitScreenController implements DragAndDropPolicy.Starter,
RemoteCallable<SplitScreenController> {
private static final String TAG = SplitScreenController.class.getSimpleName();
private final ShellTaskOrganizer mTaskOrganizer;
@@ -84,6 +91,16 @@ public class SplitScreenController implements DragAndDropPolicy.Starter {
return mImpl;
}
@Override
public Context getContext() {
return mContext;
}
@Override
public ShellExecutor getRemoteCallExecutor() {
return mMainExecutor;
}
public void onOrganizerRegistered() {
if (mStageCoordinator == null) {
// TODO: Multi-display
@@ -172,13 +189,13 @@ public class SplitScreenController implements DragAndDropPolicy.Starter {
}
}
public void startIntent(PendingIntent intent, Context context,
Intent fillInIntent, @SplitScreen.StageType int stage,
@SplitScreen.StagePosition int position, @Nullable Bundle options) {
public void startIntent(PendingIntent intent, Intent fillInIntent,
@SplitScreen.StageType int stage, @SplitScreen.StagePosition int position,
@Nullable Bundle options) {
options = resolveStartStage(stage, position, options);
try {
intent.send(context, 0, fillInIntent, null, null, null, options);
intent.send(mContext, 0, fillInIntent, null, null, null, options);
} catch (PendingIntent.CanceledException e) {
Slog.e(TAG, "Failed to launch activity", e);
}
@@ -242,121 +259,170 @@ public class SplitScreenController implements DragAndDropPolicy.Starter {
}
}
/**
* The interface for calls from outside the Shell, within the host process.
*/
@ExternalThread
private class SplitScreenImpl implements SplitScreen {
private ISplitScreenImpl mISplitScreen;
@Override
public boolean isSplitScreenVisible() {
return mMainExecutor.executeBlockingForResult(() -> {
return SplitScreenController.this.isSplitScreenVisible();
}, Boolean.class);
public ISplitScreen createExternalInterface() {
if (mISplitScreen != null) {
mISplitScreen.invalidate();
}
mISplitScreen = new ISplitScreenImpl(SplitScreenController.this);
return mISplitScreen;
}
}
/**
* The interface for calls from outside the host process.
*/
@BinderThread
private static class ISplitScreenImpl extends ISplitScreen.Stub {
private SplitScreenController mController;
private ISplitScreenListener mListener;
private final SplitScreen.SplitScreenListener mSplitScreenListener =
new SplitScreen.SplitScreenListener() {
@Override
public void onStagePositionChanged(int stage, int position) {
try {
if (mListener != null) {
mListener.onStagePositionChanged(stage, position);
}
} catch (RemoteException e) {
Slog.e(TAG, "onStagePositionChanged", e);
}
}
@Override
public void onTaskStageChanged(int taskId, int stage, boolean visible) {
try {
if (mListener != null) {
mListener.onTaskStageChanged(taskId, stage, visible);
}
} catch (RemoteException e) {
Slog.e(TAG, "onTaskStageChanged", e);
}
}
};
private final IBinder.DeathRecipient mListenerDeathRecipient =
new IBinder.DeathRecipient() {
@Override
@BinderThread
public void binderDied() {
final SplitScreenController controller = mController;
controller.getRemoteCallExecutor().execute(() -> {
mListener = null;
controller.unregisterSplitScreenListener(mSplitScreenListener);
});
}
};
public ISplitScreenImpl(SplitScreenController controller) {
mController = controller;
}
/**
* Invalidates this instance, preventing future calls from updating the controller.
*/
void invalidate() {
mController = null;
}
@Override
public boolean moveToSideStage(int taskId, int sideStagePosition) {
return mMainExecutor.executeBlockingForResult(() -> {
return SplitScreenController.this.moveToSideStage(taskId, sideStagePosition);
}, Boolean.class);
public void registerSplitScreenListener(ISplitScreenListener listener) {
executeRemoteCallWithTaskPermission(mController, "registerSplitScreenListener",
(controller) -> {
if (mListener != null) {
mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
0 /* flags */);
}
if (listener != null) {
try {
listener.asBinder().linkToDeath(mListenerDeathRecipient,
0 /* flags */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to link to death");
return;
}
}
mListener = listener;
controller.registerSplitScreenListener(mSplitScreenListener);
});
}
@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);
});
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
executeRemoteCallWithTaskPermission(mController, "unregisterSplitScreenListener",
(controller) -> {
if (mListener != null) {
mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
0 /* flags */);
}
mListener = null;
controller.unregisterSplitScreenListener(mSplitScreenListener);
});
}
@Override
public void exitSplitScreen() {
mMainExecutor.execute(() -> {
SplitScreenController.this.exitSplitScreen();
});
executeRemoteCallWithTaskPermission(mController, "exitSplitScreen",
(controller) -> {
controller.exitSplitScreen();
});
}
@Override
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
mMainExecutor.execute(() -> {
SplitScreenController.this.exitSplitScreenOnHide(exitSplitScreenOnHide);
});
executeRemoteCallWithTaskPermission(mController, "exitSplitScreenOnHide",
(controller) -> {
controller.exitSplitScreenOnHide(exitSplitScreenOnHide);
});
}
@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");
}
public void setSideStageVisibility(boolean visible) {
executeRemoteCallWithTaskPermission(mController, "setSideStageVisibility",
(controller) -> {
controller.setSideStageVisibility(visible);
});
}
@Override
public void registerSplitScreenListener(SplitScreenListener listener) {
mMainExecutor.execute(() -> {
SplitScreenController.this.registerSplitScreenListener(listener);
});
}
@Override
public void unregisterSplitScreenListener(SplitScreenListener listener) {
mMainExecutor.execute(() -> {
SplitScreenController.this.unregisterSplitScreenListener(listener);
});
public void removeFromSideStage(int taskId) {
executeRemoteCallWithTaskPermission(mController, "removeFromSideStage",
(controller) -> {
controller.removeFromSideStage(taskId);
});
}
@Override
public void startTask(int taskId, int stage, int position, @Nullable Bundle options) {
mMainExecutor.execute(() -> {
SplitScreenController.this.startTask(taskId, stage, position, options);
});
executeRemoteCallWithTaskPermission(mController, "startTask",
(controller) -> {
controller.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);
});
executeRemoteCallWithTaskPermission(mController, "startShortcut",
(controller) -> {
controller.startShortcut(packageName, shortcutId, stage, position,
options, user);
});
}
@Override
public void startIntent(PendingIntent intent, Context context, Intent fillInIntent,
int stage, int position, @Nullable Bundle options) {
mMainExecutor.execute(() -> {
SplitScreenController.this.startIntent(intent, context, fillInIntent, stage,
position, options);
});
public void startIntent(PendingIntent intent, Intent fillInIntent, int stage, int position,
@Nullable Bundle options) {
executeRemoteCallWithTaskPermission(mController, "startIntent",
(controller) -> {
controller.startIntent(intent, fillInIntent, stage, position, options);
});
}
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.wm.shell.startingsurface;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
/**
* Interface that is exposed to remote callers to manipulate starting windows.
*/
interface IStartingWindow {
/**
* Sets listener to get task launching callbacks.
*/
oneway void setStartingWindowListener(IStartingWindowListener listener) = 43;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2020 The Android Open Source Project
* 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.systemui.shared.recents;
package com.android.wm.shell.startingsurface;
/**
* Listener interface that Launcher attaches to SystemUI to get

View File

@@ -16,35 +16,15 @@
package com.android.wm.shell.startingsurface;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.StartingWindowInfo;
import java.util.function.BiConsumer;
/**
* Interface to engage starting window feature.
*/
public interface StartingSurface {
/**
* Called when a task need a starting window.
*/
void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken);
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation);
/**
* Called when the Task wants to copy the splash screen.
* @param taskId
*/
void copySplashScreenView(int taskId);
/**
* Registers the starting window listener.
*
* @param listener The callback when need a starting window.
* Returns a binder that can be passed to an external process to manipulate starting windows.
*/
void setStartingWindowListener(BiConsumer<Integer, Integer> listener);
default IStartingWindow createExternalInterface() {
return null;
}
}

View File

@@ -25,6 +25,8 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_NEW_TASK;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING;
import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -37,6 +39,9 @@ import android.window.StartingWindowInfo;
import android.window.TaskOrganizer;
import android.window.TaskSnapshot;
import androidx.annotation.BinderThread;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
@@ -58,7 +63,7 @@ import java.util.function.BiConsumer;
* constructor to keep everything synchronized.
* @hide
*/
public class StartingWindowController {
public class StartingWindowController implements RemoteCallable<StartingWindowController> {
private static final String TAG = StartingWindowController.class.getSimpleName();
static final boolean DEBUG_SPLASH_SCREEN = false;
static final boolean DEBUG_TASK_SNAPSHOT = false;
@@ -68,17 +73,17 @@ public class StartingWindowController {
private BiConsumer<Integer, Integer> mTaskLaunchingCallback;
private final StartingSurfaceImpl mImpl = new StartingSurfaceImpl();
private final Context mContext;
private final ShellExecutor mSplashScreenExecutor;
// For Car Launcher
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor) {
mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor,
new TransactionPool());
mSplashScreenExecutor = splashScreenExecutor;
this(context, splashScreenExecutor, new TransactionPool());
}
public StartingWindowController(Context context, ShellExecutor splashScreenExecutor,
TransactionPool pool) {
mContext = context;
mStartingSurfaceDrawer = new StartingSurfaceDrawer(context, splashScreenExecutor, pool);
mSplashScreenExecutor = splashScreenExecutor;
}
@@ -90,6 +95,16 @@ public class StartingWindowController {
return mImpl;
}
@Override
public Context getContext() {
return mContext;
}
@Override
public ShellExecutor getRemoteCallExecutor() {
return mSplashScreenExecutor;
}
private static class StartingTypeChecker {
TaskSnapshot mSnapshot;
@@ -188,59 +203,121 @@ public class StartingWindowController {
/**
* Called when a task need a starting window.
*/
void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
if (mTaskLaunchingCallback != null) {
mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
}
if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
} else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
}
// If prefer don't show, then don't show!
public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
mSplashScreenExecutor.execute(() -> {
final int suggestionType = mStartingTypeChecker.estimateStartingWindowType(windowInfo);
final RunningTaskInfo runningTaskInfo = windowInfo.taskInfo;
if (mTaskLaunchingCallback != null) {
mTaskLaunchingCallback.accept(runningTaskInfo.taskId, suggestionType);
}
if (suggestionType == STARTING_WINDOW_TYPE_SPLASH_SCREEN) {
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, appToken);
} else if (suggestionType == STARTING_WINDOW_TYPE_SNAPSHOT) {
final TaskSnapshot snapshot = mStartingTypeChecker.mSnapshot;
mStartingSurfaceDrawer.makeTaskSnapshotWindow(windowInfo, appToken, snapshot);
}
// If prefer don't show, then don't show!
});
}
void copySplashScreenView(int taskId) {
mStartingSurfaceDrawer.copySplashScreenView(taskId);
public void copySplashScreenView(int taskId) {
mSplashScreenExecutor.execute(() -> {
mStartingSurfaceDrawer.copySplashScreenView(taskId);
});
}
/**
* Called when the content of a task is ready to show, starting window can be removed.
*/
void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation) {
mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
mSplashScreenExecutor.execute(() -> {
mStartingSurfaceDrawer.removeStartingWindow(taskId, leash, frame, playRevealAnimation);
});
}
/**
* The interface for calls from outside the Shell, within the host process.
*/
private class StartingSurfaceImpl implements StartingSurface {
private IStartingWindowImpl mIStartingWindow;
@Override
public void addStartingWindow(StartingWindowInfo windowInfo, IBinder appToken) {
mSplashScreenExecutor.execute(() ->
StartingWindowController.this.addStartingWindow(windowInfo, appToken));
public IStartingWindowImpl createExternalInterface() {
if (mIStartingWindow != null) {
mIStartingWindow.invalidate();
}
mIStartingWindow = new IStartingWindowImpl(StartingWindowController.this);
return mIStartingWindow;
}
}
/**
* The interface for calls from outside the host process.
*/
@BinderThread
private static class IStartingWindowImpl extends IStartingWindow.Stub {
private StartingWindowController mController;
private IStartingWindowListener mListener;
private final BiConsumer<Integer, Integer> mStartingWindowListener =
this::notifyIStartingWindowListener;
private final IBinder.DeathRecipient mListenerDeathRecipient =
new IBinder.DeathRecipient() {
@Override
@BinderThread
public void binderDied() {
final StartingWindowController controller = mController;
controller.getRemoteCallExecutor().execute(() -> {
mListener = null;
controller.setStartingWindowListener(null);
});
}
};
public IStartingWindowImpl(StartingWindowController controller) {
mController = controller;
}
/**
* Invalidates this instance, preventing future calls from updating the controller.
*/
void invalidate() {
mController = null;
}
@Override
public void removeStartingWindow(int taskId, SurfaceControl leash, Rect frame,
boolean playRevealAnimation) {
mSplashScreenExecutor.execute(() ->
StartingWindowController.this.removeStartingWindow(taskId, leash, frame,
playRevealAnimation));
public void setStartingWindowListener(IStartingWindowListener listener) {
executeRemoteCallWithTaskPermission(mController, "setStartingWindowListener",
(controller) -> {
if (mListener != null) {
// Reset the old death recipient
mListener.asBinder().unlinkToDeath(mListenerDeathRecipient,
0 /* flags */);
}
if (listener != null) {
try {
listener.asBinder().linkToDeath(mListenerDeathRecipient,
0 /* flags */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to link to death");
return;
}
}
mListener = listener;
controller.setStartingWindowListener(mStartingWindowListener);
});
}
@Override
public void copySplashScreenView(int taskId) {
mSplashScreenExecutor.execute(() ->
StartingWindowController.this.copySplashScreenView(taskId));
}
private void notifyIStartingWindowListener(int taskId, int supportedType) {
if (mListener == null) {
return;
}
@Override
public void setStartingWindowListener(BiConsumer<Integer, Integer> listener) {
mSplashScreenExecutor.execute(() ->
StartingWindowController.this.setStartingWindowListener(listener));
try {
mListener.onTaskLaunching(taskId, supportedType);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to notify task launching", e);
}
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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.window.IRemoteTransition;
import android.window.TransitionFilter;
/**
* Interface that is exposed to remote callers to manipulate the transitions feature.
*/
interface IShellTransitions {
/**
* Registers a remote transition handler.
*/
oneway void registerRemote(in TransitionFilter filter,
in IRemoteTransition remoteTransition) = 1;
/**
* Unregisters a remote transition handler.
*/
oneway void unregisterRemote(in IRemoteTransition remoteTransition) = 2;
}

View File

@@ -16,6 +16,8 @@
package com.android.wm.shell.transition;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.IBinder;
@@ -23,6 +25,7 @@ import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
@@ -31,6 +34,8 @@ import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
@@ -42,6 +47,8 @@ import java.util.ArrayList;
* if the request includes a specific remote.
*/
public class RemoteTransitionHandler implements Transitions.TransitionHandler {
private static final String TAG = "RemoteTransitionHandler";
private final ShellExecutor mMainExecutor;
/** Includes remotes explicitly requested by, eg, ActivityOptions */
@@ -51,15 +58,33 @@ public class RemoteTransitionHandler implements Transitions.TransitionHandler {
private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
new ArrayList<>();
private final IBinder.DeathRecipient mTransitionDeathRecipient =
new IBinder.DeathRecipient() {
@Override
@BinderThread
public void binderDied() {
mMainExecutor.execute(() -> {
mFilters.clear();
});
}
};
RemoteTransitionHandler(@NonNull ShellExecutor mainExecutor) {
mMainExecutor = mainExecutor;
}
void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
try {
remote.asBinder().linkToDeath(mTransitionDeathRecipient, 0 /* flags */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to link to death");
return;
}
mFilters.add(new Pair<>(filter, remote));
}
void removeFiltered(IRemoteTransition remote) {
remote.asBinder().unlinkToDeath(mTransitionDeathRecipient, 0 /* flags */);
for (int i = mFilters.size() - 1; i >= 0; --i) {
if (mFilters.get(i).second == remote) {
mFilters.remove(i);

View File

@@ -26,7 +26,15 @@ import com.android.wm.shell.common.annotations.ExternalThread;
* Interface to manage remote transitions.
*/
@ExternalThread
public interface RemoteTransitions {
public interface ShellTransitions {
/**
* Returns a binder that can be passed to an external process to manipulate remote transitions.
*/
default IShellTransitions createExternalInterface() {
return null;
}
/**
* Registers a remote transition.
*/

View File

@@ -23,6 +23,8 @@ import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -51,6 +53,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.annotations.ExternalThread;
@@ -60,7 +63,7 @@ import java.util.ArrayList;
import java.util.Arrays;
/** Plays transition animations */
public class Transitions {
public class Transitions implements RemoteCallable<Transitions> {
static final String TAG = "ShellTransitions";
/** Set to {@code true} to enable shell transitions. */
@@ -73,7 +76,7 @@ public class Transitions {
private final ShellExecutor mAnimExecutor;
private final TransitionPlayerImpl mPlayerImpl;
private final RemoteTransitionHandler mRemoteTransitionHandler;
private final RemoteTransitionImpl mImpl = new RemoteTransitionImpl();
private final ShellTransitionImpl mImpl = new ShellTransitionImpl();
/** List of possible handlers. Ordered by specificity (eg. tapped back to front). */
private final ArrayList<TransitionHandler> mHandlers = new ArrayList<>();
@@ -87,10 +90,6 @@ 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 Context context, @NonNull ShellExecutor mainExecutor,
@NonNull ShellExecutor animExecutor) {
@@ -126,6 +125,20 @@ public class Transitions {
mRemoteTransitionHandler = null;
}
public ShellTransitions asRemoteTransitions() {
return mImpl;
}
@Override
public Context getContext() {
return mContext;
}
@Override
public ShellExecutor getRemoteCallExecutor() {
return mMainExecutor;
}
private void dispatchAnimScaleSetting(float scale) {
for (int i = mHandlers.size() - 1; i >= 0; --i) {
mHandlers.get(i).setAnimScaleSetting(scale);
@@ -134,8 +147,8 @@ public class Transitions {
/** Create an empty/non-registering transitions object for system-ui tests. */
@VisibleForTesting
public static RemoteTransitions createEmptyForTesting() {
return new RemoteTransitions() {
public static ShellTransitions createEmptyForTesting() {
return new ShellTransitions() {
@Override
public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
@androidx.annotation.NonNull IRemoteTransition remoteTransition) {
@@ -426,24 +439,74 @@ public class Transitions {
}
}
/**
* The interface for calls from outside the Shell, within the host process.
*/
@ExternalThread
private class RemoteTransitionImpl implements RemoteTransitions {
private class ShellTransitionImpl implements ShellTransitions {
private IShellTransitionsImpl mIShellTransitions;
@Override
public IShellTransitions createExternalInterface() {
if (mIShellTransitions != null) {
mIShellTransitions.invalidate();
}
mIShellTransitions = new IShellTransitionsImpl(Transitions.this);
return mIShellTransitions;
}
@Override
public void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
Transitions.this.registerRemote(filter, remoteTransition);
mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
});
}
@Override
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
Transitions.this.unregisterRemote(remoteTransition);
mRemoteTransitionHandler.removeFiltered(remoteTransition);
});
}
}
/**
* The interface for calls from outside the host process.
*/
@BinderThread
private static class IShellTransitionsImpl extends IShellTransitions.Stub {
private Transitions mTransitions;
IShellTransitionsImpl(Transitions transitions) {
mTransitions = transitions;
}
/**
* Invalidates this instance, preventing future calls from updating the controller.
*/
void invalidate() {
mTransitions = null;
}
@Override
public void registerRemote(@NonNull TransitionFilter filter,
@NonNull IRemoteTransition remoteTransition) {
executeRemoteCallWithTaskPermission(mTransitions, "registerRemote",
(transitions) -> {
transitions.mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
});
}
@Override
public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
executeRemoteCallWithTaskPermission(mTransitions, "unregisterRemote",
(transitions) -> {
transitions.mRemoteTransitionHandler.removeFiltered(remoteTransition);
});
}
}
private class SettingsObserver extends ContentObserver {
SettingsObserver() {

View File

@@ -205,7 +205,7 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -217,12 +217,12 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_RIGHT), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -234,12 +234,12 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
reset(mSplitScreenStarter);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_SPLIT_BOTTOM), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -251,7 +251,7 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -263,7 +263,7 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_UNDEFINED), eq(STAGE_POSITION_UNDEFINED), any());
}
@@ -276,13 +276,13 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_LEFT, TYPE_SPLIT_RIGHT);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), 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).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}
@@ -295,13 +295,13 @@ public class DragAndDropPolicyTest {
mPolicy.getTargets(mInsets), TYPE_FULLSCREEN, TYPE_SPLIT_TOP, TYPE_SPLIT_BOTTOM);
mPolicy.handleDrop(filterTargetByType(targets, TYPE_FULLSCREEN), mActivityClipData);
verify(mSplitScreenStarter).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), 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).startIntent(any(), any(), any(),
verify(mSplitScreenStarter).startIntent(any(), any(),
eq(STAGE_TYPE_SIDE), eq(STAGE_POSITION_BOTTOM_OR_RIGHT), any());
}

View File

@@ -16,8 +16,6 @@
package com.android.systemui.shared.recents;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -25,14 +23,11 @@ import android.os.Bundle;
import android.os.UserHandle;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.ISplitScreenListener;
import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteTransitionCompat;
/**
* Temporary callbacks into SystemUI.
* Next id = 44
*/
interface ISystemUiProxy {
@@ -134,16 +129,6 @@ interface ISystemUiProxy {
*/
void onQuickSwitchToNewTask(int rotation) = 25;
/**
* Start the one-handed mode.
*/
void startOneHandedMode() = 26;
/**
* Stop the one-handed mode.
*/
void stopOneHandedMode() = 27;
/**
* Handle the provided image as if it was a screenshot.
*/
@@ -155,65 +140,5 @@ interface ISystemUiProxy {
*/
void expandNotificationPanel() = 29;
/**
* Registers a RemoteTransitionCompat that will handle transitions. This parameter bundles an
* IRemoteTransition and a filter that must pass for it.
*/
void registerRemoteTransition(in RemoteTransitionCompat remoteTransition) = 32;
/** Unegisters a RemoteTransitionCompat that will handle transitions. */
void unregisterRemoteTransition(in RemoteTransitionCompat remoteTransition) = 33;
// SplitScreen APIs...copied from SplitScreen.java
/**
* Stage position isn't specified normally meaning to use what ever it is currently set to.
*/
//int STAGE_POSITION_UNDEFINED = -1;
/**
* Specifies that a stage is positioned at the top half of the screen if
* in portrait mode or at the left half of the screen if in landscape mode.
*/
//int STAGE_POSITION_TOP_OR_LEFT = 0;
/**
* Specifies that a stage is positioned at the bottom half of the screen if
* in portrait mode or at the right half of the screen if in landscape mode.
*/
//int STAGE_POSITION_BOTTOM_OR_RIGHT = 1;
/**
* Stage type isn't specified normally meaning to use what ever the default is.
* E.g. exit split-screen and launch the app in fullscreen.
*/
//int STAGE_TYPE_UNDEFINED = -1;
/**
* The main stage type.
* @see MainStage
*/
//int STAGE_TYPE_MAIN = 0;
/**
* The side stage type.
* @see SideStage
*/
//int STAGE_TYPE_SIDE = 1;
void registerSplitScreenListener(in ISplitScreenListener listener) = 34;
void unregisterSplitScreenListener(in ISplitScreenListener listener) = 35;
/** Hides the side-stage if it is currently visible. */
void setSideStageVisibility(in boolean visible) = 36;
/** Removes the split-screen stages. */
void exitSplitScreen() = 37;
/** @param exitSplitScreenOnHide if to exit split-screen if both stages are not visible. */
void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) = 38;
void startTask(in int taskId, in int stage, in int position, in Bundle options) = 39;
void startShortcut(in String packageName, in String shortcutId, in int stage, in int position,
in Bundle options, in UserHandle user) = 40;
void startIntent(
in PendingIntent intent, in Intent fillInIntent, in int stage, in int position,
in Bundle options) = 41;
void removeFromSideStage(in int taskId) = 42;
/**
* Sets listener to get task launching callbacks.
*/
void setStartingWindowListener(IStartingWindowListener listener) = 43;
// Next id = 44
}

View File

@@ -43,6 +43,16 @@ public class QuickStepContract {
public static final String KEY_EXTRA_SUPPORTS_WINDOW_CORNERS = "extra_supports_window_corners";
// See IPip.aidl
public static final String KEY_EXTRA_SHELL_PIP = "extra_shell_pip";
// See ISplitScreen.aidl
public static final String KEY_EXTRA_SHELL_SPLIT_SCREEN = "extra_shell_split_screen";
// See IOneHanded.aidl
public static final String KEY_EXTRA_SHELL_ONE_HANDED = "extra_shell_one_handed";
// See IShellTransitions.aidl
public static final String KEY_EXTRA_SHELL_SHELL_TRANSITIONS =
"extra_shell_shell_transitions";
// See IStartingWindow.aidl
public static final String KEY_EXTRA_SHELL_STARTING_WINDOW =
"extra_shell_starting_window";
public static final String NAV_BAR_MODE_2BUTTON_OVERLAY =
WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY;

View File

@@ -34,7 +34,7 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.ShellTransitions;
import java.util.Optional;
@@ -87,7 +87,7 @@ public interface SysUIComponent {
Builder setShellCommandHandler(Optional<ShellCommandHandler> shellDump);
@BindsInstance
Builder setTransitions(RemoteTransitions t);
Builder setTransitions(ShellTransitions t);
@BindsInstance
Builder setStartingSurface(Optional<StartingSurface> s);

View File

@@ -33,7 +33,7 @@ import com.android.wm.shell.onehanded.OneHanded;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.ShellTransitions;
import java.util.Optional;
@@ -98,7 +98,7 @@ public interface WMComponent {
Optional<TaskViewFactory> getTaskViewFactory();
@WMSingleton
RemoteTransitions getTransitions();
ShellTransitions getTransitions();
@WMSingleton
Optional<StartingSurface> getStartingSurface();

View File

@@ -25,7 +25,11 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INPUT_MONITOR;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
@@ -36,15 +40,12 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_T
import android.annotation.FloatRange;
import android.app.ActivityTaskManager;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
@@ -58,14 +59,12 @@ import android.os.Looper;
import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Log;
import android.view.InputMonitor;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.accessibility.AccessibilityManager;
import android.window.IRemoteTransition;
import androidx.annotation.NonNull;
@@ -84,14 +83,11 @@ import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISplitScreenListener;
import com.android.systemui.shared.recents.IStartingWindowListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteTransitionCompat;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -103,7 +99,7 @@ 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.startingsurface.StartingSurface;
import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.ShellTransitions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -111,7 +107,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.inject.Inject;
@@ -151,7 +146,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final ScreenshotHelper mScreenshotHelper;
private final Optional<OneHanded> mOneHandedOptional;
private final CommandQueue mCommandQueue;
private final RemoteTransitions mShellTransitions;
private final ShellTransitions mShellTransitions;
private final Optional<StartingSurface> mStartingSurface;
private Region mActiveNavBarRegion;
@@ -168,8 +163,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
private float mWindowCornerRadius;
private boolean mSupportsRoundedCornersOnWindows;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
private final ArraySet<IRemoteTransition> mRemoteTransitions = new ArraySet<>();
private IStartingWindowListener mIStartingWindowListener;
@VisibleForTesting
public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -413,21 +406,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
@Override
public void setStartingWindowListener(IStartingWindowListener listener) {
if (!verifyCaller("setStartingWindowListener")) {
return;
}
mIStartingWindowListener = listener;
final long token = Binder.clearCallingIdentity();
try {
mStartingSurface.ifPresent(s ->
s.setStartingWindowListener(mStartingWindowListener));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void onQuickSwitchToNewTask(@Surface.Rotation int rotation) {
if (!verifyCaller("onQuickSwitchToNewTask")) {
@@ -441,32 +419,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
@Override
public void startOneHandedMode() {
if (!verifyCaller("startOneHandedMode")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded());
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void stopOneHandedMode() {
if (!verifyCaller("stopOneHandedMode")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded());
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
Insets visibleInsets, Task.TaskKey task) {
@@ -495,158 +447,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
@Override
public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) {
if (!verifyCaller("registerRemoteTransition")) return;
final long binderToken = Binder.clearCallingIdentity();
try {
mRemoteTransitions.add(remoteTransition.getTransition());
mShellTransitions.registerRemote(
remoteTransition.getFilter(), remoteTransition.getTransition());
} finally {
Binder.restoreCallingIdentity(binderToken);
}
}
@Override
public void unregisterRemoteTransition(RemoteTransitionCompat remoteTransition) {
if (!verifyCaller("registerRemoteTransition")) return;
final long binderToken = Binder.clearCallingIdentity();
try {
mRemoteTransitions.remove(remoteTransition.getTransition());
mShellTransitions.unregisterRemote(remoteTransition.getTransition());
} finally {
Binder.restoreCallingIdentity(binderToken);
}
}
@Override
public void registerSplitScreenListener(ISplitScreenListener listener) {
if (!verifyCaller("registerSplitScreenListener")) {
return;
}
mISplitScreenListener = listener;
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(
s -> s.registerSplitScreenListener(mSplitScreenListener));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void unregisterSplitScreenListener(ISplitScreenListener listener) {
if (!verifyCaller("unregisterSplitScreenListener")) {
return;
}
mISplitScreenListener = null;
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(
s -> s.unregisterSplitScreenListener(mSplitScreenListener));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void setSideStageVisibility(boolean visible) {
if (!verifyCaller("setSideStageVisibility")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s -> s.setSideStageVisibility(visible));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void exitSplitScreen() {
if (!verifyCaller("exitSplitScreen")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s -> s.exitSplitScreen());
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
if (!verifyCaller("exitSplitScreenOnHide")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s -> s.exitSplitScreenOnHide(exitSplitScreenOnHide));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void startTask(int taskId, int stage, int position, Bundle options) {
if (!verifyCaller("startTask")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(
s -> s.startTask(taskId, stage, position, options));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void startShortcut(String packageName, String shortcutId, int stage, int position,
Bundle options, UserHandle user) {
if (!verifyCaller("startShortcut")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s ->
s.startShortcut(packageName, shortcutId, stage, position, options, user));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void startIntent(PendingIntent intent, Intent fillInIntent,
int stage, int position, Bundle options) {
if (!verifyCaller("startIntent")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(s ->
s.startIntent(intent, mContext, fillInIntent, stage, position, options));
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override
public void removeFromSideStage(int taskId) {
if (!verifyCaller("removeFromSideStage")) {
return;
}
final long token = Binder.clearCallingIdentity();
try {
mSplitScreenOptional.ifPresent(
s -> s.removeFromSideStage(taskId));
} finally {
Binder.restoreCallingIdentity(token);
}
}
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {
@@ -701,8 +501,20 @@ public class OverviewProxyService extends CurrentUserTracker implements
params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
mPipOptional.ifPresent((pip) -> params.putBinder(KEY_EXTRA_SHELL_PIP,
mPipOptional.ifPresent((pip) -> params.putBinder(
KEY_EXTRA_SHELL_PIP,
pip.createExternalInterface().asBinder()));
mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
KEY_EXTRA_SHELL_SPLIT_SCREEN,
splitscreen.createExternalInterface().asBinder()));
mOneHandedOptional.ifPresent((onehanded) -> params.putBinder(
KEY_EXTRA_SHELL_ONE_HANDED,
onehanded.createExternalInterface().asBinder()));
params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
mShellTransitions.createExternalInterface().asBinder());
mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
KEY_EXTRA_SHELL_STARTING_WINDOW,
startingwindow.createExternalInterface().asBinder()));
try {
mOverviewProxy.onInitialize(params);
@@ -744,39 +556,10 @@ public class OverviewProxyService extends CurrentUserTracker implements
private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
this::notifySplitScreenBoundsChanged;
private final BiConsumer<Integer, Integer> mStartingWindowListener =
this::notifyTaskLaunching;
// This is the death handler for the binder from the launcher service
private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
= this::cleanupAfterDeath;
private ISplitScreenListener mISplitScreenListener;
private final SplitScreen.SplitScreenListener mSplitScreenListener =
new SplitScreen.SplitScreenListener() {
@Override
public void onStagePositionChanged(int stage, int position) {
try {
if (mISplitScreenListener != null) {
mISplitScreenListener.onStagePositionChanged(stage, position);
}
} catch (RemoteException e) {
Log.e(TAG_OPS, "onStagePositionChanged", e);
}
}
@Override
public void onTaskStageChanged(int taskId, int stage, boolean visible) {
try {
if (mISplitScreenListener != null) {
mISplitScreenListener.onTaskStageChanged(taskId, stage, visible);
}
} catch (RemoteException e) {
Log.e(TAG_OPS, "onTaskStageChanged", e);
}
}
};
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
@@ -789,7 +572,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
Optional<Lazy<StatusBar>> statusBarOptionalLazy,
Optional<OneHanded> oneHandedOptional,
BroadcastDispatcher broadcastDispatcher,
RemoteTransitions shellTransitions,
ShellTransitions shellTransitions,
Optional<StartingSurface> startingSurface) {
super(broadcastDispatcher);
mContext = context;
@@ -906,18 +689,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
}
}
private void notifyTaskLaunching(int taskId, int supportedType) {
if (mIStartingWindowListener == null) {
return;
}
try {
mIStartingWindowListener.onTaskLaunching(taskId, supportedType);
} catch (RemoteException e) {
Log.e(TAG_OPS, "Failed to call notifyTaskLaunching()", e);
}
}
private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
boolean bouncerShowing) {
mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
@@ -961,12 +732,6 @@ public class OverviewProxyService extends CurrentUserTracker implements
// Clean up the minimized state if launcher dies
mLegacySplitScreenOptional.ifPresent(
splitScreen -> splitScreen.setMinimized(false));
// Clean up any registered remote transitions
for (int i = mRemoteTransitions.size() - 1; i >= 0; --i) {
mShellTransitions.unregisterRemote(mRemoteTransitions.valueAt(i));
}
mRemoteTransitions.clear();
}
public void startConnectionToCurrentUser() {

View File

@@ -81,7 +81,7 @@ import com.android.wm.shell.splitscreen.SplitScreen;
import com.android.wm.shell.splitscreen.SplitScreenController;
import com.android.wm.shell.startingsurface.StartingSurface;
import com.android.wm.shell.startingsurface.StartingWindowController;
import com.android.wm.shell.transition.RemoteTransitions;
import com.android.wm.shell.transition.ShellTransitions;
import com.android.wm.shell.transition.Transitions;
import java.util.Optional;
@@ -399,8 +399,8 @@ public abstract class WMShellBaseModule {
@WMSingleton
@Provides
static RemoteTransitions provideRemoteTransitions(Transitions transitions) {
return Transitions.asRemoteTransitions(transitions);
static ShellTransitions provideRemoteTransitions(Transitions transitions) {
return transitions.asRemoteTransitions();
}
@WMSingleton
@@ -521,10 +521,10 @@ public abstract class WMShellBaseModule {
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
Optional<AppPairsController> appPairsOptional,
Optional<StartingSurface> startingSurface,
Optional<PipTouchHandler> pipTouchHandlerOptional,
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
StartingWindowController startingWindow,
@ShellMainThread ShellExecutor mainExecutor) {
return new ShellInitImpl(displayImeController,
dragAndDropController,
@@ -532,10 +532,10 @@ public abstract class WMShellBaseModule {
legacySplitScreenOptional,
splitScreenOptional,
appPairsOptional,
startingSurface,
pipTouchHandlerOptional,
fullscreenTaskListener,
transitions,
startingWindow,
mainExecutor);
}