Merge "Ensure the current controller when handling a remote call in the Shell" into main
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 5600664..8c36554 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -18,7 +18,6 @@
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_HOME;
 import static com.android.window.flags.Flags.predictiveBackSystemAnims;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 317e00a..d9055fb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -518,7 +518,7 @@
     }
 
     private ExternalInterfaceBinder createExternalInterface() {
-        return new BubbleController.IBubblesImpl(this);
+        return new IBubblesImpl(this);
     }
 
     @VisibleForTesting
@@ -2354,6 +2354,8 @@
         @Override
         public void invalidate() {
             mController = null;
+            // Unregister the listeners to ensure any binder death recipients are unlinked
+            mListener.unregister();
         }
 
         @Override
@@ -2531,17 +2533,6 @@
 
         private CachedState mCachedState = new CachedState();
 
-        private IBubblesImpl mIBubbles;
-
-        @Override
-        public IBubbles createExternalInterface() {
-            if (mIBubbles != null) {
-                mIBubbles.invalidate();
-            }
-            mIBubbles = new IBubblesImpl(BubbleController.this);
-            return mIBubbles;
-        }
-
         @Override
         public boolean isBubbleNotificationSuppressedFromShade(String key, String groupKey) {
             return mCachedState.isBubbleNotificationSuppressedFromShade(key, groupKey);
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
deleted file mode 100644
index b29058b..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExecutorUtils.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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/ExternalInterfaceBinder.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java
index aa5b0cb..d6f4d81 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ExternalInterfaceBinder.java
@@ -16,7 +16,11 @@
 
 package com.android.wm.shell.common;
 
+import android.Manifest;
 import android.os.IBinder;
+import android.util.Slog;
+
+import java.util.function.Consumer;
 
 /**
  * An interface for binders which can be registered to be sent to other processes.
@@ -31,4 +35,40 @@
      * Returns the IBinder to send.
      */
     IBinder asBinder();
+
+    /**
+     * Checks that the caller has the MANAGE_ACTIVITY_TASKS permission and executes the given
+     * callback.
+     */
+    default <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.
+     */
+    default <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("ExternalInterfaceBinder", "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
index 30f535b..0d90fb7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/RemoteCallable.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 
 /**
- * An interface for controllers that can receive remote calls.
+ * An interface for controllers (of type T) that can receive remote calls.
  */
 public interface RemoteCallable<T> {
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 83a8d4c..0cdd181 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -54,7 +54,6 @@
 import com.android.wm.shell.ShellTaskOrganizer
 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.ExternalInterfaceBinder
 import com.android.wm.shell.common.LaunchAdjacentController
 import com.android.wm.shell.common.MultiInstanceHelper
@@ -1471,13 +1470,13 @@
         }
 
         override fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition?) {
-            ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "showDesktopApps") { c ->
+            executeRemoteCallWithTaskPermission(controller, "showDesktopApps") { c ->
                 c.showDesktopApps(displayId, remoteTransition)
             }
         }
 
         override fun showDesktopApp(taskId: Int) {
-            ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "showDesktopApp") { c ->
+            executeRemoteCallWithTaskPermission(controller, "showDesktopApp") { c ->
                 c.moveTaskToFront(taskId)
             }
         }
@@ -1495,7 +1494,7 @@
 
         override fun getVisibleTaskCount(displayId: Int): Int {
             val result = IntArray(1)
-            ExecutorUtils.executeRemoteCallWithTaskPermission(
+            executeRemoteCallWithTaskPermission(
                 controller,
                 "getVisibleTaskCount",
                 { controller -> result[0] = controller.getVisibleTaskCount(displayId) },
@@ -1505,7 +1504,7 @@
         }
 
         override fun onDesktopSplitSelectAnimComplete(taskInfo: RunningTaskInfo) {
-            ExecutorUtils.executeRemoteCallWithTaskPermission(
+            executeRemoteCallWithTaskPermission(
                 controller,
                 "onDesktopSplitSelectAnimComplete"
             ) { c ->
@@ -1519,13 +1518,13 @@
                 "IDesktopModeImpl: set task listener=%s",
                 listener ?: "null"
             )
-            ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "setTaskListener") { _ ->
+            executeRemoteCallWithTaskPermission(controller, "setTaskListener") { _ ->
                 listener?.let { remoteListener.register(it) } ?: remoteListener.unregister()
             }
         }
 
         override fun moveToDesktop(taskId: Int, transitionSource: DesktopModeTransitionSource) {
-            ExecutorUtils.executeRemoteCallWithTaskPermission(controller, "moveToDesktop") { c ->
+            executeRemoteCallWithTaskPermission(controller, "moveToDesktop") { c ->
                 c.moveToDesktop(taskId, transitionSource = transitionSource)
             }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
index 9aa5f4f..0acc7df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/changes.md
@@ -54,8 +54,8 @@
   extend `ExternalInterfaceBinder` and implement `invalidate()` to ensure it doesn't hold long
   references to the outer controller
 - Make the controller implement `RemoteCallable<T>`, and have all incoming calls use one of
-  the `ExecutorUtils.executeRemoteCallWithTaskPermission()` calls to verify the caller's identity
-  and ensure the call happens on the main shell thread and not the binder thread
+  the `executeRemoteCallWithTaskPermission()` calls to verify the caller's identity and ensure the
+  call happens on the main shell thread and not the binder thread
 - Inject `ShellController` and add the instance of the implementation as external interface
 - In Launcher, update `TouchInteractionService` to pass the interface to `SystemUIProxy`, and then
   call the SystemUIProxy method as needed in that code
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 7e70d6a..c374eb8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -32,7 +32,6 @@
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DRAG_AND_DROP;
 
 import android.app.ActivityManager;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index 39b9000..962309f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -19,7 +19,6 @@
 import static android.os.UserHandle.myUserId;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE;
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING;
 import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING;
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 85f9194..de105c0 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
@@ -22,7 +22,6 @@
 import static android.view.WindowManager.INPUT_CONSUMER_PIP;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_PIP_TRANSITION;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.pip.PipAnimationController.ANIM_TYPE_ALPHA;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND;
 import static com.android.wm.shell.pip.PipAnimationController.TRANSITION_DIRECTION_LEAVE_PIP;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index f5afeea..1846720 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -19,7 +19,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_PIP;
 
 import android.app.ActivityManager;
@@ -391,6 +390,7 @@
         @Override
         public void invalidate() {
             mController = null;
+            // Unregister the listener to ensure any registered binder death recipients are unlinked
             mListener.unregister();
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 863202d..9d16246 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -20,7 +20,6 @@
 import static android.content.pm.PackageManager.FEATURE_PC;
 
 import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS;
 
 import android.app.ActivityManager;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index b9d70e1..dd219d3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -24,7 +24,6 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.common.MultiInstanceHelper.getComponent;
 import static com.android.wm.shell.common.MultiInstanceHelper.getShortcutComponent;
 import static com.android.wm.shell.common.MultiInstanceHelper.samePackage;
@@ -1241,8 +1240,9 @@
         @Override
         public void invalidate() {
             mController = null;
-            // Unregister the listener to ensure any registered binder death recipients are unlinked
+            // Unregister the listeners to ensure any binder death recipients are unlinked
             mListener.unregister();
+            mSelectListener.unregister();
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index bec4ba3..fa084c58 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -23,7 +23,6 @@
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_WINDOWLESS;
 
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
 
 import android.app.ActivityManager.RunningTaskInfo;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
index b1a1e59..299da13 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/HomeTransitionObserver.java
@@ -133,5 +133,7 @@
      */
     public void invalidate(Transitions transitions) {
         transitions.unregisterObserver(this);
+        // Unregister the listener to ensure any registered binder death recipients are unlinked
+        mListener.unregister();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index b056c18..b2180db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -35,7 +35,6 @@
 import static android.window.TransitionInfo.FLAG_STARTING_WINDOW_TRANSFER_RECIPIENT;
 
 import static com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary;
-import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
 import static com.android.wm.shell.shared.TransitionUtil.isClosingType;
 import static com.android.wm.shell.shared.TransitionUtil.isOpeningType;
 import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;