diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 43d733c8c74ed..a7c2bf1ec0d73 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3014,7 +3014,8 @@ package android.companion.virtual { public static interface VirtualDeviceManager.ActivityListener { method public void onDisplayEmpty(int); - method public void onTopActivityChanged(int, @NonNull android.content.ComponentName); + method @Deprecated public void onTopActivityChanged(int, @NonNull android.content.ComponentName); + method public default void onTopActivityChanged(int, @NonNull android.content.ComponentName, int); } public static interface VirtualDeviceManager.IntentInterceptorCallback { diff --git a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl index a46dc534da562..fc7f85cceefca 100644 --- a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl +++ b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl @@ -30,8 +30,9 @@ oneway interface IVirtualDeviceActivityListener { * * @param displayId The display ID on which the activity change happened. * @param topActivity The component name of the top activity. + * @param userId The user ID associated with the top activity. */ - void onTopActivityChanged(int displayId, in ComponentName topActivity); + void onTopActivityChanged(int displayId, in ComponentName topActivity, in int userId); /** * Called when the display becomes empty (e.g. if the user hits back on the last diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index d585e8f8d38da..3e6b380be1f4d 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -27,6 +27,7 @@ import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.UserIdInt; import android.app.PendingIntent; import android.companion.AssociationInfo; import android.companion.virtual.audio.VirtualAudioDevice; @@ -378,13 +379,16 @@ public final class VirtualDeviceManager { new IVirtualDeviceActivityListener.Stub() { @Override - public void onTopActivityChanged(int displayId, ComponentName topActivity) { + public void onTopActivityChanged(int displayId, ComponentName topActivity, + @UserIdInt int userId) { final long token = Binder.clearCallingIdentity(); try { synchronized (mActivityListenersLock) { for (int i = 0; i < mActivityListeners.size(); i++) { mActivityListeners.valueAt(i) .onTopActivityChanged(displayId, topActivity); + mActivityListeners.valueAt(i) + .onTopActivityChanged(displayId, topActivity, userId); } } } finally { @@ -1087,9 +1091,24 @@ public final class VirtualDeviceManager { * * @param displayId The display ID on which the activity change happened. * @param topActivity The component name of the top activity. + * @deprecated Use {@link #onTopActivityChanged(int, ComponentName, int)} instead */ void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity); + /** + * Called when the top activity is changed. + * + *

Note: When there are no activities running on the virtual display, the + * {@link #onDisplayEmpty(int)} will be called. If the value topActivity is cached, it + * should be cleared when {@link #onDisplayEmpty(int)} is called. + * + * @param displayId The display ID on which the activity change happened. + * @param topActivity The component name of the top activity. + * @param userId The user ID associated with the top activity. + */ + default void onTopActivityChanged(int displayId, @NonNull ComponentName topActivity, + @UserIdInt int userId) {} + /** * Called when the display becomes empty (e.g. if the user hits back on the last * activity of the root task). @@ -1115,6 +1134,12 @@ public final class VirtualDeviceManager { mExecutor.execute(() -> mActivityListener.onTopActivityChanged(displayId, topActivity)); } + public void onTopActivityChanged(int displayId, ComponentName topActivity, + @UserIdInt int userId) { + mExecutor.execute(() -> + mActivityListener.onTopActivityChanged(displayId, topActivity, userId)); + } + public void onDisplayEmpty(int displayId) { mExecutor.execute(() -> mActivityListener.onDisplayEmpty(displayId)); } diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java index 535dc4e78c89d..c2700536f8490 100644 --- a/core/java/android/window/DisplayWindowPolicyController.java +++ b/core/java/android/window/DisplayWindowPolicyController.java @@ -19,6 +19,7 @@ package android.window; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import android.annotation.NonNull; +import android.annotation.UserIdInt; import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Intent; @@ -137,7 +138,7 @@ public abstract class DisplayWindowPolicyController { /** * This is called when the top activity of the display is changed. */ - public void onTopActivityChanged(ComponentName topActivity, int uid) {} + public void onTopActivityChanged(ComponentName topActivity, int uid, @UserIdInt int userId) {} /** * This is called when the apps that contains running activities on the display has changed. diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java index 6b2e893a55c9d..e52f1d9c61db3 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -23,6 +23,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.UserIdInt; import android.app.WindowConfiguration; import android.app.compat.CompatChanges; import android.companion.virtual.VirtualDeviceManager.ActivityListener; @@ -302,14 +303,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } @Override - public void onTopActivityChanged(ComponentName topActivity, int uid) { + public void onTopActivityChanged(ComponentName topActivity, int uid, @UserIdInt int userId) { // Don't send onTopActivityChanged() callback when topActivity is null because it's defined // as @NonNull in ActivityListener interface. Sends onDisplayEmpty() callback instead when // there is no activity running on virtual display. if (mActivityListener != null && topActivity != null) { // Post callback on the main thread so it doesn't block activity launching mHandler.post(() -> - mActivityListener.onTopActivityChanged(mDisplayId, topActivity)); + mActivityListener.onTopActivityChanged(mDisplayId, topActivity, userId)); } } diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index 3100277eb7624..7fce442377208 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -26,6 +26,7 @@ import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringRes; +import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityOptions; import android.app.PendingIntent; @@ -137,7 +138,18 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub @Override public void onTopActivityChanged(int displayId, ComponentName topActivity) { try { - mActivityListener.onTopActivityChanged(displayId, topActivity); + mActivityListener.onTopActivityChanged(displayId, topActivity, + UserHandle.USER_NULL); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to call mActivityListener", e); + } + } + + @Override + public void onTopActivityChanged(int displayId, ComponentName topActivity, + @UserIdInt int userId) { + try { + mActivityListener.onTopActivityChanged(displayId, topActivity, userId); } catch (RemoteException e) { Slog.w(TAG, "Unable to call mActivityListener", e); } diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java index 154fb0cecac32..1fb97f97f4216 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java +++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.app.WindowConfiguration; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.os.Process; import android.os.UserHandle; import android.util.ArraySet; import android.util.Slog; @@ -138,10 +139,14 @@ class DisplayWindowPolicyControllerHelper { true /* includeOverlays */); if (topActivity != mTopRunningActivity) { mTopRunningActivity = topActivity; - mDisplayWindowPolicyController.onTopActivityChanged( - topActivity == null ? null : topActivity.info.getComponentName(), - topActivity == null - ? UserHandle.USER_NULL : topActivity.info.applicationInfo.uid); + if (topActivity == null) { + mDisplayWindowPolicyController.onTopActivityChanged(null, Process.INVALID_UID, + UserHandle.USER_NULL); + } else { + mDisplayWindowPolicyController.onTopActivityChanged( + topActivity.info.getComponentName(), topActivity.info.applicationInfo.uid, + topActivity.mUserId); + } } // Update running uid. diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java index b2abd44254d95..19d1d83f5e737 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerTests.java @@ -33,7 +33,7 @@ import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ActivityInfo; -import android.os.UserHandle; +import android.os.Process; import android.util.ArraySet; import android.view.Display; import android.window.DisplayWindowPolicyController; @@ -101,7 +101,7 @@ public class DisplayWindowPolicyControllerTests extends WindowTestsBase { int uidAmount = (expectedUid0 && expectedUid1) ? 2 : (expectedUid0 || expectedUid1) ? 1 : 0; assertEquals(expectedTopActivity == null ? null : expectedTopActivity.info.getComponentName(), mDwpc.mTopActivity); - assertEquals(expectedTopActivity == null ? UserHandle.USER_NULL : + assertEquals(expectedTopActivity == null ? Process.INVALID_UID : expectedTopActivity.info.applicationInfo.uid, mDwpc.mTopActivityUid); assertEquals(uidAmount, mDwpc.mRunningUids.size()); assertTrue(mDwpc.mRunningUids.contains(TEST_USER_0_ID) == expectedUid0); @@ -224,7 +224,7 @@ public class DisplayWindowPolicyControllerTests extends WindowTestsBase { new ComponentName("fake.package", "DisallowedActivity"); ComponentName mTopActivity = null; - int mTopActivityUid = UserHandle.USER_NULL; + int mTopActivityUid = Process.INVALID_UID; ArraySet mRunningUids = new ArraySet<>(); @Override @@ -254,8 +254,8 @@ public class DisplayWindowPolicyControllerTests extends WindowTestsBase { } @Override - public void onTopActivityChanged(ComponentName topActivity, int uid) { - super.onTopActivityChanged(topActivity, uid); + public void onTopActivityChanged(ComponentName topActivity, int uid, int userId) { + super.onTopActivityChanged(topActivity, uid, userId); mTopActivity = topActivity; mTopActivityUid = uid; }