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:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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() {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user