diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp index 1b5dc8bdbcaab..3f03302de474f 100644 --- a/libs/WindowManager/Shell/Android.bp +++ b/libs/WindowManager/Shell/Android.bp @@ -38,6 +38,14 @@ filegroup { path: "src", } +filegroup { + name: "wm_shell-aidls", + srcs: [ + "src/**/*.aidl", + ], + path: "src", +} + // TODO(b/168581922) protologtool do not support kotlin(*.kt) filegroup { name: "wm_shell-sources-kt", @@ -98,7 +106,7 @@ android_library { ":wm_shell_protolog_src", // TODO(b/168581922) protologtool do not support kotlin(*.kt) ":wm_shell-sources-kt", - "src/**/I*.aidl", + ":wm_shell-aidls", ], resource_dirs: [ "res", diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java index eaed24d6195ab..d451f4a0661bb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellCommandHandlerImpl.java @@ -47,21 +47,7 @@ public final class ShellCommandHandlerImpl { private final ShellExecutor mMainExecutor; private final HandlerImpl mImpl = new HandlerImpl(); - public static ShellCommandHandler create( - ShellTaskOrganizer shellTaskOrganizer, - Optional legacySplitScreenOptional, - Optional splitScreenOptional, - Optional pipOptional, - Optional oneHandedOptional, - Optional hideDisplayCutout, - Optional appPairsOptional, - ShellExecutor mainExecutor) { - return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional, - splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout, - appPairsOptional, mainExecutor).mImpl; - } - - private ShellCommandHandlerImpl( + public ShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, Optional splitScreenOptional, @@ -80,6 +66,10 @@ public final class ShellCommandHandlerImpl { mMainExecutor = mainExecutor; } + public ShellCommandHandler asShellCommandHandler() { + return mImpl; + } + /** Dumps WM Shell internal state. */ private void dump(PrintWriter pw) { mShellTaskOrganizer.dump(pw, ""); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java index 85bd24c1c2bff..9abda68fbfd7c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellInitImpl.java @@ -51,31 +51,7 @@ public class ShellInitImpl { private final InitImpl mImpl = new InitImpl(); - public static ShellInit create(DisplayImeController displayImeController, - DragAndDropController dragAndDropController, - ShellTaskOrganizer shellTaskOrganizer, - Optional legacySplitScreenOptional, - Optional splitScreenOptional, - Optional appPairsOptional, - Optional startingSurfaceOptional, - Optional pipTouchHandlerOptional, - FullscreenTaskListener fullscreenTaskListener, - Transitions transitions, - ShellExecutor mainExecutor) { - return new ShellInitImpl(displayImeController, - dragAndDropController, - shellTaskOrganizer, - legacySplitScreenOptional, - splitScreenOptional, - appPairsOptional, - startingSurfaceOptional, - pipTouchHandlerOptional, - fullscreenTaskListener, - transitions, - mainExecutor).mImpl; - } - - private ShellInitImpl(DisplayImeController displayImeController, + public ShellInitImpl(DisplayImeController displayImeController, DragAndDropController dragAndDropController, ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, @@ -99,6 +75,10 @@ public class ShellInitImpl { mStartingSurfaceOptional = startingSurfaceOptional; } + public ShellInit asShellInit() { + return mImpl; + } + private void init() { // Start listening for display changes mDisplayImeController.startMonitorDisplays(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java new file mode 100644 index 0000000000000..b29058b1f2041 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java @@ -0,0 +1,64 @@ +/* + * 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.common; + +import android.Manifest; +import android.util.Slog; + +import java.util.function.Consumer; + +/** + * Helpers for working with executors + */ +public class ExecutorUtils { + + /** + * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given + * callback. + */ + public static void executeRemoteCallWithTaskPermission(RemoteCallable controllerInstance, + String log, Consumer callback) { + executeRemoteCallWithTaskPermission(controllerInstance, log, callback, + false /* blocking */); + } + + /** + * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given + * callback. + */ + public static void executeRemoteCallWithTaskPermission(RemoteCallable controllerInstance, + String log, Consumer callback, boolean blocking) { + if (controllerInstance == null) return; + + final RemoteCallable controller = controllerInstance; + controllerInstance.getContext().enforceCallingPermission( + Manifest.permission.MANAGE_ACTIVITY_TASKS, log); + if (blocking) { + try { + controllerInstance.getRemoteCallExecutor().executeBlocking(() -> { + callback.accept((T) controller); + }); + } catch (InterruptedException e) { + Slog.e("ExecutorUtils", "Remote call failed", e); + } + } else { + controllerInstance.getRemoteCallExecutor().execute(() -> { + callback.accept((T) controller); + }); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java new file mode 100644 index 0000000000000..30f535ba940c2 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java @@ -0,0 +1,34 @@ +/* + * 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.common; + +import android.content.Context; + +/** + * An interface for controllers that can receive remote calls. + */ +public interface RemoteCallable { + /** + * Returns a context used for permission checking. + */ + Context getContext(); + + /** + * Returns the executor to post the handler callback to. + */ + ShellExecutor getRemoteCallExecutor(); +} \ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl new file mode 100644 index 0000000000000..a6ffa6e445846 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl @@ -0,0 +1,63 @@ +/* + * 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.pip; + +import android.app.PictureInPictureParams; +import android.content.ComponentName; +import android.content.pm.ActivityInfo; +import android.graphics.Rect; + +import com.android.wm.shell.pip.IPipAnimationListener; + +/** + * Interface that is exposed to remote callers to manipulate the Pip feature. + */ +interface IPip { + + /** + * Notifies that Activity is about to be swiped to home with entering PiP transition and + * queries the destination bounds for PiP depends on Launcher's rotation and shelf height. + * + * @param componentName ComponentName represents the Activity + * @param activityInfo ActivityInfo tied to the Activity + * @param pictureInPictureParams PictureInPictureParams tied to the Activity + * @param launcherRotation Launcher rotation to calculate the PiP destination bounds + * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds + * @return destination bounds the PiP window should land into + */ + Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo, + in PictureInPictureParams pictureInPictureParams, + int launcherRotation, int shelfHeight) = 1; + + /** + * Notifies the swiping Activity to PiP onto home transition is finished + * + * @param componentName ComponentName represents the Activity + * @param destinationBounds the destination bounds the PiP window lands into + */ + oneway void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 2; + + /** + * Sets listener to get pinned stack animation callbacks. + */ + oneway void setPinnedStackAnimationListener(IPipAnimationListener listener) = 3; + + /** + * Sets the shelf height and visibility. + */ + oneway void setShelfHeight(boolean visible, int shelfHeight) = 4; +} diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl similarity index 68% rename from packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl rename to libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl index 97aa512ea7df5..2569b780c1bb1 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IPinnedStackAnimationListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPipAnimationListener.aidl @@ -14,15 +14,14 @@ * limitations under the License. */ -package com.android.systemui.shared.recents; +package com.android.wm.shell.pip; /** - * Listener interface that Launcher attaches to SystemUI to get - * pinned stack animation callbacks. + * Listener interface that Launcher attaches to SystemUI to get Pip animation callbacks. */ -oneway interface IPinnedStackAnimationListener { +oneway interface IPipAnimationListener { /** - * Notifies the pinned stack animation is started. + * Notifies the listener that the Pip animation is started. */ - void onPinnedStackAnimationStarted(); + void onPipAnimationStarted(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index d14c3e3c0dd4d..6d4773bdeb1f6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -16,15 +16,10 @@ package com.android.wm.shell.pip; -import android.annotation.Nullable; -import android.app.PictureInPictureParams; -import android.content.ComponentName; -import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.graphics.Rect; import com.android.wm.shell.common.annotations.ExternalThread; -import com.android.wm.shell.pip.phone.PipTouchHandler; import java.io.PrintWriter; import java.util.function.Consumer; @@ -34,6 +29,14 @@ import java.util.function.Consumer; */ @ExternalThread public interface Pip { + + /** + * Returns a binder that can be passed to an external process to manipulate PIP. + */ + default IPip createExternalInterface() { + return null; + } + /** * Expand PIP, it's possible that specific request to activate the window via Alt-tab. */ @@ -108,30 +111,6 @@ public interface Pip { */ default void showPictureInPictureMenu() {} - /** - * Called by Launcher when swiping an auto-pip enabled Activity to home starts - * @param componentName {@link ComponentName} represents the Activity entering PiP - * @param activityInfo {@link ActivityInfo} tied to the Activity - * @param pictureInPictureParams {@link PictureInPictureParams} tied to the Activity - * @param launcherRotation Rotation Launcher is in - * @param shelfHeight Shelf height when landing PiP window onto Launcher - * @return Destination bounds of PiP window based on the parameters passed in - */ - default Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, - int launcherRotation, int shelfHeight) { - return null; - } - - /** - * Called by Launcher when swiping an auto-pip enable Activity to home finishes - * @param componentName {@link ComponentName} represents the Activity entering PiP - * @param destinationBounds Destination bounds of PiP window - */ - default void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - return; - } - /** * Called by NavigationBar in order to listen in for PiP bounds change. This is mostly used * for times where the PiP bounds could conflict with SystemUI elements, such as a stashed diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 9a584c67f97c0..501b90ea68283 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -21,8 +21,10 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; import static android.view.WindowManager.INPUT_CONSUMER_PIP; +import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission; import static com.android.wm.shell.pip.PipAnimationController.isOutPipDirection; +import android.Manifest; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.PictureInPictureParams; @@ -33,6 +35,7 @@ import android.content.pm.ActivityInfo; import android.content.pm.ParceledListSlice; import android.content.res.Configuration; import android.graphics.Rect; +import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -44,6 +47,7 @@ import android.view.DisplayInfo; import android.view.WindowManagerGlobal; import android.window.WindowContainerTransaction; +import androidx.annotation.BinderThread; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -51,9 +55,13 @@ import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; +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; +import com.android.wm.shell.pip.IPip; +import com.android.wm.shell.pip.IPipAnimationListener; import com.android.wm.shell.pip.PinnedStackListenerForwarder; import com.android.wm.shell.pip.Pip; import com.android.wm.shell.pip.PipBoundsAlgorithm; @@ -71,7 +79,8 @@ import java.util.function.Consumer; /** * Manages the picture-in-picture (PIP) UI and states for Phones. */ -public class PipController implements PipTransitionController.PipTransitionCallback { +public class PipController implements PipTransitionController.PipTransitionCallback, + RemoteCallable { private static final String TAG = "PipController"; private Context mContext; @@ -85,12 +94,12 @@ public class PipController implements PipTransitionController.PipTransitionCallb private PipBoundsState mPipBoundsState; private PipTouchHandler mTouchHandler; private PipTransitionController mPipTransitionController; - protected final PipImpl mImpl = new PipImpl(); + protected final PipImpl mImpl; private final Rect mTmpInsetBounds = new Rect(); private boolean mIsInFixedRotation; - private Consumer mPinnedStackAnimationRecentsCallback; + private IPipAnimationListener mPinnedStackAnimationRecentsCallback; protected PhonePipMenuController mMenuController; protected PipTaskOrganizer mPipTaskOrganizer; @@ -264,6 +273,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } mContext = context; + mImpl = new PipImpl(); mWindowManagerShellWrapper = windowManagerShellWrapper; mDisplayController = displayController; mPipBoundsAlgorithm = pipBoundsAlgorithm; @@ -366,6 +376,16 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); } + @Override + public Context getContext() { + return mContext; + } + + @Override + public ShellExecutor getRemoteCallExecutor() { + return mMainExecutor; + } + private void onConfigurationChanged(Configuration newConfig) { mPipBoundsAlgorithm.onConfigurationChanged(mContext); mTouchHandler.onConfigurationChanged(); @@ -474,7 +494,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipTaskOrganizer.setOneShotAnimationType(animationType); } - private void setPinnedStackAnimationListener(Consumer callback) { + private void setPinnedStackAnimationListener(IPipAnimationListener callback) { mPinnedStackAnimationRecentsCallback = callback; } @@ -512,7 +532,11 @@ public class PipController implements PipTransitionController.PipTransitionCallb // Disable touches while the animation is running mTouchHandler.setTouchEnabled(false); if (mPinnedStackAnimationRecentsCallback != null) { - mPinnedStackAnimationRecentsCallback.accept(true); + try { + mPinnedStackAnimationRecentsCallback.onPipAnimationStarted(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call onPinnedStackAnimationStarted()", e); + } } } @@ -638,7 +662,21 @@ public class PipController implements PipTransitionController.PipTransitionCallb mPipInputConsumer.dump(pw, innerPrefix); } + /** + * The interface for calls from outside the Shell, within the host process. + */ private class PipImpl implements Pip { + private IPipImpl mIPip; + + @Override + public IPip createExternalInterface() { + if (mIPip != null) { + mIPip.invalidate(); + } + mIPip = new IPipImpl(PipController.this); + return mIPip; + } + @Override public void hidePipMenu(Runnable onStartCallback, Runnable onEndCallback) { mMainExecutor.execute(() -> { @@ -695,13 +733,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); } - @Override - public void setPinnedStackAnimationListener(Consumer callback) { - mMainExecutor.execute(() -> { - PipController.this.setPinnedStackAnimationListener(callback); - }); - } - @Override public void setPinnedStackAnimationType(int animationType) { mMainExecutor.execute(() -> { @@ -723,29 +754,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb }); } - @Override - public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, int launcherRotation, - int shelfHeight) { - Rect[] result = new Rect[1]; - try { - mMainExecutor.executeBlocking(() -> { - result[0] = PipController.this.startSwipePipToHome(componentName, activityInfo, - pictureInPictureParams, launcherRotation, shelfHeight); - }); - } catch (InterruptedException e) { - Slog.e(TAG, "Failed to start swipe pip to home"); - } - return result[0]; - } - - @Override - public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - mMainExecutor.execute(() -> { - PipController.this.stopSwipePipToHome(componentName, destinationBounds); - }); - } - @Override public void dump(PrintWriter pw) { try { @@ -757,4 +765,89 @@ public class PipController implements PipTransitionController.PipTransitionCallb } } } + + /** + * The interface for calls from outside the host process. + */ + @BinderThread + private static class IPipImpl extends IPip.Stub { + private PipController mController; + private IPipAnimationListener mListener; + private final IBinder.DeathRecipient mListenerDeathRecipient = + new IBinder.DeathRecipient() { + @Override + @BinderThread + public void binderDied() { + final PipController controller = mController; + controller.getRemoteCallExecutor().execute(() -> { + mListener = null; + controller.setPinnedStackAnimationListener(null); + }); + } + }; + + IPipImpl(PipController controller) { + mController = controller; + } + + /** + * Invalidates this instance, preventing future calls from updating the controller. + */ + void invalidate() { + mController = null; + } + + @Override + public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, + PictureInPictureParams pictureInPictureParams, int launcherRotation, + int shelfHeight) { + Rect[] result = new Rect[1]; + executeRemoteCallWithTaskPermission(mController, "startSwipePipToHome", + (controller) -> { + result[0] = controller.startSwipePipToHome(componentName, activityInfo, + pictureInPictureParams, launcherRotation, shelfHeight); + }, true /* blocking */); + return result[0]; + } + + @Override + public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { + executeRemoteCallWithTaskPermission(mController, "stopSwipePipToHome", + (controller) -> { + controller.stopSwipePipToHome(componentName, destinationBounds); + }); + } + + @Override + public void setShelfHeight(boolean visible, int height) { + executeRemoteCallWithTaskPermission(mController, "setShelfHeight", + (controller) -> { + controller.setShelfHeight(visible, height); + }); + } + + @Override + public void setPinnedStackAnimationListener(IPipAnimationListener listener) { + executeRemoteCallWithTaskPermission(mController, "setPinnedStackAnimationListener", + (controller) -> { + if (mListener != null) { + // Reset the old death recipient + mListener.asBinder().unlinkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } + if (listener != null) { + // Register the death recipient for the new listener to clear the listener + try { + listener.asBinder().linkToDeath(mListenerDeathRecipient, + 0 /* flags */); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to link to death"); + return; + } + } + mListener = listener; + controller.setPinnedStackAnimationListener(listener); + }); + } + } } diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp index 09e9675a32776..f98a959346d36 100644 --- a/packages/SystemUI/shared/Android.bp +++ b/packages/SystemUI/shared/Android.bp @@ -41,6 +41,7 @@ android_library { srcs: [ "src/**/*.java", "src/**/I*.aidl", + ":wm_shell-aidls", ], static_libs: [ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 5126284475300..e89ae38cb4d52 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -17,10 +17,7 @@ package com.android.systemui.shared.recents; import android.app.PendingIntent; -import android.app.PictureInPictureParams; -import android.content.ComponentName; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.graphics.Bitmap; import android.graphics.Insets; import android.graphics.Rect; @@ -28,7 +25,6 @@ import android.os.Bundle; import android.os.UserHandle; import android.view.MotionEvent; -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; import com.android.systemui.shared.recents.ISplitScreenListener; import com.android.systemui.shared.recents.IStartingWindowListener; import com.android.systemui.shared.recents.model.Task; @@ -40,13 +36,6 @@ import com.android.systemui.shared.system.RemoteTransitionCompat; */ interface ISystemUiProxy { - /** - * Proxies SurfaceControl.screenshotToBuffer(). - * @Removed - * GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer, - * int maxLayer, boolean useIdentityTransform, int rotation) = 0; - */ - /** * Begins screen pinning on the provided {@param taskId}. */ @@ -114,11 +103,6 @@ interface ISystemUiProxy { */ void stopScreenPinning() = 17; - /** - * Sets the shelf height and visibility. - */ - void setShelfHeight(boolean visible, int shelfHeight) = 20; - /** * Handle the provided image as if it was a screenshot. * @@ -138,11 +122,6 @@ interface ISystemUiProxy { */ void notifySwipeToHomeFinished() = 23; - /** - * Sets listener to get pinned stack animation callbacks. - */ - void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) = 24; - /** * Notifies that quickstep will switch to a new task * @param rotation indicates which Surface.Rotation the gesture was started in @@ -170,29 +149,6 @@ interface ISystemUiProxy { */ void expandNotificationPanel() = 29; - /** - * Notifies that Activity is about to be swiped to home with entering PiP transition and - * queries the destination bounds for PiP depends on Launcher's rotation and shelf height. - * - * @param componentName ComponentName represents the Activity - * @param activityInfo ActivityInfo tied to the Activity - * @param pictureInPictureParams PictureInPictureParams tied to the Activity - * @param launcherRotation Launcher rotation to calculate the PiP destination bounds - * @param shelfHeight Shelf height of launcher to calculate the PiP destination bounds - * @return destination bounds the PiP window should land into - */ - Rect startSwipePipToHome(in ComponentName componentName, in ActivityInfo activityInfo, - in PictureInPictureParams pictureInPictureParams, - int launcherRotation, int shelfHeight) = 30; - - /** - * Notifies the swiping Activity to PiP onto home transition is finished - * - * @param componentName ComponentName represents the Activity - * @param destinationBounds the destination bounds the PiP window lands into - */ - void stopSwipePipToHome(in ComponentName componentName, in Rect destinationBounds) = 31; - /** * Registers a RemoteTransitionCompat that will handle transitions. This parameter bundles an * IRemoteTransition and a filter that must pass for it. diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 937c1df103151..55a6d34d65728 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -41,6 +41,8 @@ public class QuickStepContract { public static final String KEY_EXTRA_INPUT_MONITOR = "extra_input_monitor"; public static final String KEY_EXTRA_WINDOW_CORNER_RADIUS = "extra_window_corner_radius"; 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"; public static final String NAV_BAR_MODE_2BUTTON_OVERLAY = WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON_OVERLAY; diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index 8951605846a10..9851ea1c9b174 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -25,6 +25,7 @@ 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_PIP; 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; @@ -83,7 +84,6 @@ 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.IPinnedStackAnimationListener; import com.android.systemui.shared.recents.ISplitScreenListener; import com.android.systemui.shared.recents.IStartingWindowListener; import com.android.systemui.shared.recents.ISystemUiProxy; @@ -156,7 +156,6 @@ public class OverviewProxyService extends CurrentUserTracker implements private Region mActiveNavBarRegion; - private IPinnedStackAnimationListener mIPinnedStackAnimationListener; private IOverviewProxy mOverviewProxy; private int mConnectionBackoffAttempts; private boolean mBound; @@ -382,20 +381,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } } - @Override - public void setShelfHeight(boolean visible, int shelfHeight) { - if (!verifyCaller("setShelfHeight")) { - return; - } - final long token = Binder.clearCallingIdentity(); - try { - mPipOptional.ifPresent( - pip -> pip.setShelfHeight(visible, shelfHeight)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - @Override public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen, Insets visibleInsets, int taskId) { @@ -423,21 +408,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } } - @Override - public void setPinnedStackAnimationListener(IPinnedStackAnimationListener listener) { - if (!verifyCaller("setPinnedStackAnimationListener")) { - return; - } - mIPinnedStackAnimationListener = listener; - final long token = Binder.clearCallingIdentity(); - try { - mPipOptional.ifPresent( - pip -> pip.setPinnedStackAnimationListener(mPinnedStackAnimationCallback)); - } finally { - Binder.restoreCallingIdentity(token); - } - } - @Override public void setStartingWindowListener(IStartingWindowListener listener) { if (!verifyCaller("setStartingWindowListener")) { @@ -520,38 +490,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } } - @Override - public Rect startSwipePipToHome(ComponentName componentName, ActivityInfo activityInfo, - PictureInPictureParams pictureInPictureParams, - int launcherRotation, int shelfHeight) { - if (!verifyCaller("startSwipePipToHome")) { - return null; - } - final long binderToken = Binder.clearCallingIdentity(); - try { - return mPipOptional.map(pip -> - pip.startSwipePipToHome(componentName, activityInfo, - pictureInPictureParams, launcherRotation, shelfHeight)) - .orElse(null); - } finally { - Binder.restoreCallingIdentity(binderToken); - } - } - - @Override - public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) { - if (!verifyCaller("stopSwipePipToHome")) { - return; - } - final long binderToken = Binder.clearCallingIdentity(); - try { - mPipOptional.ifPresent(pip -> pip.stopSwipePipToHome( - componentName, destinationBounds)); - } finally { - Binder.restoreCallingIdentity(binderToken); - } - } - @Override public void registerRemoteTransition(RemoteTransitionCompat remoteTransition) { if (!verifyCaller("registerRemoteTransition")) return; @@ -757,6 +695,10 @@ public class OverviewProxyService extends CurrentUserTracker implements params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder()); 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, + pip.createExternalInterface().asBinder())); + try { mOverviewProxy.onInitialize(params); } catch (RemoteException e) { @@ -796,8 +738,6 @@ public class OverviewProxyService extends CurrentUserTracker implements private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged; private final BiConsumer mSplitScreenBoundsChangeListener = this::notifySplitScreenBoundsChanged; - private final Consumer mPinnedStackAnimationCallback = - this::notifyPinnedStackAnimationStarted; private final BiConsumer mStartingWindowListener = this::notifyTaskLaunching; @@ -961,17 +901,6 @@ public class OverviewProxyService extends CurrentUserTracker implements } } - private void notifyPinnedStackAnimationStarted(Boolean isAnimationStarted) { - if (mIPinnedStackAnimationListener == null) { - return; - } - try { - mIPinnedStackAnimationListener.onPinnedStackAnimationStarted(); - } catch (RemoteException e) { - Log.e(TAG_OPS, "Failed to call onPinnedStackAnimationStarted()", e); - } - } - private void notifyTaskLaunching(int taskId, int supportedType) { if (mIStartingWindowListener == null) { return; diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java index 3f4ec8539d38a..01cdb09bf083d 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java @@ -509,7 +509,13 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides - static ShellInit provideShellInit(DisplayImeController displayImeController, + static ShellInit provideShellInit(ShellInitImpl impl) { + return impl.asShellInit(); + } + + @WMSingleton + @Provides + static ShellInitImpl provideShellInitImpl(DisplayImeController displayImeController, DragAndDropController dragAndDropController, ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, @@ -520,7 +526,7 @@ public abstract class WMShellBaseModule { FullscreenTaskListener fullscreenTaskListener, Transitions transitions, @ShellMainThread ShellExecutor mainExecutor) { - return ShellInitImpl.create(displayImeController, + return new ShellInitImpl(displayImeController, dragAndDropController, shellTaskOrganizer, legacySplitScreenOptional, @@ -539,7 +545,13 @@ public abstract class WMShellBaseModule { */ @WMSingleton @Provides - static Optional provideShellCommandHandler( + static Optional provideShellCommandHandler(ShellCommandHandlerImpl impl) { + return Optional.of(impl.asShellCommandHandler()); + } + + @WMSingleton + @Provides + static ShellCommandHandlerImpl provideShellCommandHandlerImpl( ShellTaskOrganizer shellTaskOrganizer, Optional legacySplitScreenOptional, Optional splitScreenOptional, @@ -548,8 +560,8 @@ public abstract class WMShellBaseModule { Optional hideDisplayCutout, Optional appPairsOptional, @ShellMainThread ShellExecutor mainExecutor) { - return Optional.of(ShellCommandHandlerImpl.create(shellTaskOrganizer, + return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional, splitScreenOptional, pipOptional, oneHandedOptional, - hideDisplayCutout, appPairsOptional, mainExecutor)); + hideDisplayCutout, appPairsOptional, mainExecutor); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java deleted file mode 100644 index 25104b8b1d20d..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.recents; - -import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.pm.PackageManager; -import android.os.RemoteException; -import android.test.suitebuilder.annotation.SmallTest; -import android.testing.AndroidTestingRunner; -import android.testing.TestableContext; -import android.testing.TestableLooper; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.model.SysUiState; -import com.android.systemui.navigationbar.NavigationBarController; -import com.android.systemui.navigationbar.NavigationModeController; -import com.android.systemui.shared.recents.IPinnedStackAnimationListener; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.NotificationShadeWindowController; -import com.android.systemui.statusbar.phone.StatusBar; -import com.android.wm.shell.legacysplitscreen.LegacySplitScreen; -import com.android.wm.shell.pip.Pip; -import com.android.wm.shell.splitscreen.SplitScreen; -import com.android.wm.shell.startingsurface.StartingSurface; -import com.android.wm.shell.transition.RemoteTransitions; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -import java.util.Optional; - -import dagger.Lazy; - -/** - * Unit tests for {@link com.android.systemui.recents.OverviewProxyService} - */ -@SmallTest -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -public class OverviewProxyServiceTest extends SysuiTestCase { - private OverviewProxyService mSpiedOverviewProxyService; - private TestableContext mSpiedContext; - - @Mock private BroadcastDispatcher mMockBroadcastDispatcher; - @Mock private CommandQueue mMockCommandQueue; - @Mock private Lazy mMockNavBarControllerLazy; - @Mock private IPinnedStackAnimationListener mMockPinnedStackAnimationListener; - @Mock private NavigationModeController mMockNavModeController; - @Mock private NotificationShadeWindowController mMockStatusBarWinController; - @Mock private Optional mMockPipOptional; - @Mock private Optional mMockLegacySplitScreenOptional; - @Mock private Optional mMockSplitScreenOptional; - @Mock private Optional> mMockStatusBarOptionalLazy; - @Mock private Optional mMockOneHandedOptional; - @Mock private PackageManager mPackageManager; - @Mock private SysUiState mMockSysUiState; - @Mock private RemoteTransitions mMockTransitions; - @Mock private Optional mStartingSurface; - - @Before - public void setUp() throws RemoteException { - MockitoAnnotations.initMocks(this); - - mSpiedContext = spy(mContext); - - when(mPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false); - when(mSpiedContext.getPackageManager()).thenReturn(mPackageManager); - - mSpiedOverviewProxyService = spy(new OverviewProxyService(mSpiedContext, mMockCommandQueue, - mMockNavBarControllerLazy, mMockNavModeController, mMockStatusBarWinController, - mMockSysUiState, mMockPipOptional, mMockLegacySplitScreenOptional, - mMockSplitScreenOptional, mMockStatusBarOptionalLazy, mMockOneHandedOptional, - mMockBroadcastDispatcher, mMockTransitions, mStartingSurface)); - } - - @Test - public void testNonPipDevice_shouldNotNotifySwipeToHomeFinished() throws RemoteException { - mSpiedOverviewProxyService.mSysUiProxy.notifySwipeToHomeFinished(); - - verify(mMockPipOptional, never()).ifPresent(any()); - } - - @Test - public void testNonPipDevice_shouldNotSetPinnedStackAnimationListener() throws RemoteException { - mSpiedOverviewProxyService.mSysUiProxy.setPinnedStackAnimationListener( - mMockPinnedStackAnimationListener); - - verify(mMockPipOptional, never()).ifPresent(any()); - } - - @Test - public void testNonPipDevice_shouldNotSetShelfHeight() throws RemoteException { - mSpiedOverviewProxyService.mSysUiProxy.setShelfHeight(true /* visible */, - 100 /* shelfHeight */); - - verify(mMockPipOptional, never()).ifPresent(any()); - } -}