1/ Add mechanism to expose shell feature directly (for Pip)
- Also split impl and controller for ShellInit/ShellCommandHandler
(as with ag/13502602)
- Example implementation of exposing a subset of the Pip interface to
Launcher directly. This has the benefit of reducing unnecessary code
in SysUI just to pipe calls to the Shell.
The controller implements the binder interface which is collected
and exposed to Launcher when it binds to the overview service
and Launcher can call through the binders directly.
Note: this requires the shared lib to also build with the Shell
interfaces so changes to the Shell aidls will still require updating
the shared lib (until the shared lib prebuilt can removed).
Bug: 180074017
Test: atest WMShellUnitTests
Test: Verify Pip calls from Launcher work
Change-Id: Id74114da6a6a73d32c957f84fce5bbe23e87ba01
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 1b5dc8b..3f03302 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -38,6 +38,14 @@
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 @@
":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 eaed24d..d451f4a 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 @@
private final ShellExecutor mMainExecutor;
private final HandlerImpl mImpl = new HandlerImpl();
- public static ShellCommandHandler create(
- ShellTaskOrganizer shellTaskOrganizer,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
- Optional<SplitScreenController> splitScreenOptional,
- Optional<Pip> pipOptional,
- Optional<OneHandedController> oneHandedOptional,
- Optional<HideDisplayCutoutController> hideDisplayCutout,
- Optional<AppPairsController> appPairsOptional,
- ShellExecutor mainExecutor) {
- return new ShellCommandHandlerImpl(shellTaskOrganizer, legacySplitScreenOptional,
- splitScreenOptional, pipOptional, oneHandedOptional, hideDisplayCutout,
- appPairsOptional, mainExecutor).mImpl;
- }
-
- private ShellCommandHandlerImpl(
+ public ShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
@@ -80,6 +66,10 @@
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 85bd24c..9abda68 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 @@
private final InitImpl mImpl = new InitImpl();
- public static ShellInit create(DisplayImeController displayImeController,
- DragAndDropController dragAndDropController,
- ShellTaskOrganizer shellTaskOrganizer,
- Optional<LegacySplitScreenController> legacySplitScreenOptional,
- Optional<SplitScreenController> splitScreenOptional,
- Optional<AppPairsController> appPairsOptional,
- Optional<StartingSurface> startingSurfaceOptional,
- Optional<PipTouchHandler> 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<LegacySplitScreenController> legacySplitScreenOptional,
@@ -99,6 +75,10 @@
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 0000000..b29058b
--- /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 <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
+ String log, Consumer<T> callback) {
+ executeRemoteCallWithTaskPermission(controllerInstance, log, callback,
+ false /* blocking */);
+ }
+
+ /**
+ * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
+ * callback.
+ */
+ public static <T> void executeRemoteCallWithTaskPermission(RemoteCallable<T> controllerInstance,
+ String log, Consumer<T> callback, boolean blocking) {
+ if (controllerInstance == null) return;
+
+ final RemoteCallable<T> 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 0000000..30f535b
--- /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<T> {
+ /**
+ * 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 0000000..a6ffa6e
--- /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 97aa512..2569b78 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 d14c3e3c..6d4773b 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 @@
*/
@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.
*/
@@ -109,30 +112,6 @@
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
* PiP and the Back-from-Edge gesture.
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 9a584c6..501b90e 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.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.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.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.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 @@
/**
* Manages the picture-in-picture (PIP) UI and states for Phones.
*/
-public class PipController implements PipTransitionController.PipTransitionCallback {
+public class PipController implements PipTransitionController.PipTransitionCallback,
+ RemoteCallable<PipController> {
private static final String TAG = "PipController";
private Context mContext;
@@ -85,12 +94,12 @@
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<Boolean> mPinnedStackAnimationRecentsCallback;
+ private IPipAnimationListener mPinnedStackAnimationRecentsCallback;
protected PhonePipMenuController mMenuController;
protected PipTaskOrganizer mPipTaskOrganizer;
@@ -264,6 +273,7 @@
}
mContext = context;
+ mImpl = new PipImpl();
mWindowManagerShellWrapper = windowManagerShellWrapper;
mDisplayController = displayController;
mPipBoundsAlgorithm = pipBoundsAlgorithm;
@@ -366,6 +376,16 @@
});
}
+ @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 @@
mPipTaskOrganizer.setOneShotAnimationType(animationType);
}
- private void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
+ private void setPinnedStackAnimationListener(IPipAnimationListener callback) {
mPinnedStackAnimationRecentsCallback = callback;
}
@@ -512,7 +532,11 @@
// 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 @@
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(() -> {
@@ -696,13 +734,6 @@
}
@Override
- public void setPinnedStackAnimationListener(Consumer<Boolean> callback) {
- mMainExecutor.execute(() -> {
- PipController.this.setPinnedStackAnimationListener(callback);
- });
- }
-
- @Override
public void setPinnedStackAnimationType(int animationType) {
mMainExecutor.execute(() -> {
PipController.this.setPinnedStackAnimationType(animationType);
@@ -724,29 +755,6 @@
}
@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 {
mMainExecutor.executeBlocking(() -> {
@@ -757,4 +765,89 @@
}
}
}
+
+ /**
+ * 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 09e9675a..f98a959 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -41,6 +41,7 @@
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 5126284..e89ae38 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.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;
@@ -41,13 +37,6 @@
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}.
*/
void startScreenPinning(int taskId) = 1;
@@ -115,11 +104,6 @@
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.
*
* Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
@@ -139,11 +123,6 @@
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
*/
@@ -171,29 +150,6 @@
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 937c1df..55a6d34 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 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 8951605..9851ea1 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 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.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 @@
private Region mActiveNavBarRegion;
- private IPinnedStackAnimationListener mIPinnedStackAnimationListener;
private IOverviewProxy mOverviewProxy;
private int mConnectionBackoffAttempts;
private boolean mBound;
@@ -383,20 +382,6 @@
}
@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) {
// Deprecated
@@ -424,21 +409,6 @@
}
@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")) {
return;
@@ -521,38 +491,6 @@
}
@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;
final long binderToken = Binder.clearCallingIdentity();
@@ -757,6 +695,10 @@
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 @@
private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
this::notifySplitScreenBoundsChanged;
- private final Consumer<Boolean> mPinnedStackAnimationCallback =
- this::notifyPinnedStackAnimationStarted;
private final BiConsumer<Integer, Integer> mStartingWindowListener =
this::notifyTaskLaunching;
@@ -961,17 +901,6 @@
}
}
- 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 3f4ec85..01cdb09 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 @@
@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<LegacySplitScreenController> legacySplitScreenOptional,
@@ -520,7 +526,7 @@
FullscreenTaskListener fullscreenTaskListener,
Transitions transitions,
@ShellMainThread ShellExecutor mainExecutor) {
- return ShellInitImpl.create(displayImeController,
+ return new ShellInitImpl(displayImeController,
dragAndDropController,
shellTaskOrganizer,
legacySplitScreenOptional,
@@ -539,7 +545,13 @@
*/
@WMSingleton
@Provides
- static Optional<ShellCommandHandler> provideShellCommandHandler(
+ static Optional<ShellCommandHandler> provideShellCommandHandler(ShellCommandHandlerImpl impl) {
+ return Optional.of(impl.asShellCommandHandler());
+ }
+
+ @WMSingleton
+ @Provides
+ static ShellCommandHandlerImpl provideShellCommandHandlerImpl(
ShellTaskOrganizer shellTaskOrganizer,
Optional<LegacySplitScreenController> legacySplitScreenOptional,
Optional<SplitScreenController> splitScreenOptional,
@@ -548,8 +560,8 @@
Optional<HideDisplayCutoutController> hideDisplayCutout,
Optional<AppPairsController> 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 25104b8..0000000
--- 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<NavigationBarController> mMockNavBarControllerLazy;
- @Mock private IPinnedStackAnimationListener mMockPinnedStackAnimationListener;
- @Mock private NavigationModeController mMockNavModeController;
- @Mock private NotificationShadeWindowController mMockStatusBarWinController;
- @Mock private Optional<Pip> mMockPipOptional;
- @Mock private Optional<LegacySplitScreen> mMockLegacySplitScreenOptional;
- @Mock private Optional<SplitScreen> mMockSplitScreenOptional;
- @Mock private Optional<Lazy<StatusBar>> mMockStatusBarOptionalLazy;
- @Mock private Optional<com.android.wm.shell.onehanded.OneHanded> mMockOneHandedOptional;
- @Mock private PackageManager mPackageManager;
- @Mock private SysUiState mMockSysUiState;
- @Mock private RemoteTransitions mMockTransitions;
- @Mock private Optional<StartingSurface> 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());
- }
-}