diff options
7 files changed, 71 insertions, 4 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e76676842468..7bfa878a7c0b 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3543,6 +3543,7 @@ package android.companion.virtual { public static interface VirtualDeviceManager.ActivityListener { method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onActivityLaunchBlocked(int, @NonNull android.content.ComponentName, @NonNull android.os.UserHandle, @Nullable android.content.IntentSender); method public void onDisplayEmpty(int); + method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onSecureWindowHidden(int); method @FlaggedApi("android.companion.virtualdevice.flags.activity_control_api") public default void onSecureWindowShown(int, @NonNull android.content.ComponentName, @NonNull android.os.UserHandle); method @Deprecated public void onTopActivityChanged(int, @NonNull android.content.ComponentName); method public default void onTopActivityChanged(int, @NonNull android.content.ComponentName, int); diff --git a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl index 767f52a92566..448793d12bcb 100644 --- a/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl +++ b/core/java/android/companion/virtual/IVirtualDeviceActivityListener.aidl @@ -63,4 +63,11 @@ oneway interface IVirtualDeviceActivityListener { * @param user The user associated with the activity. */ void onSecureWindowShown(int displayId, in ComponentName componentName, in UserHandle user); + + /** + * Called when a secure surface is no longer shown on the device. + * + * @param displayId The display ID on which the secure surface was shown. + */ + void onSecureWindowHidden(int displayId); } diff --git a/core/java/android/companion/virtual/VirtualDeviceInternal.java b/core/java/android/companion/virtual/VirtualDeviceInternal.java index d63a4434d7d8..42c74414ecd9 100644 --- a/core/java/android/companion/virtual/VirtualDeviceInternal.java +++ b/core/java/android/companion/virtual/VirtualDeviceInternal.java @@ -166,6 +166,20 @@ public class VirtualDeviceInternal { Binder.restoreCallingIdentity(token); } } + + @Override + public void onSecureWindowHidden(int displayId) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mActivityListenersLock) { + for (int i = 0; i < mActivityListeners.size(); i++) { + mActivityListeners.valueAt(i).onSecureWindowHidden(displayId); + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + } }; private final IVirtualDeviceSoundEffectListener mSoundEffectListener = @@ -617,6 +631,10 @@ public class VirtualDeviceInternal { mExecutor.execute(() -> mActivityListener.onSecureWindowShown(displayId, componentName, user)); } + + public void onSecureWindowHidden(int displayId) { + mExecutor.execute(() -> mActivityListener.onSecureWindowHidden(displayId)); + } } /** diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index 6ea7834243a4..b3f09a98d623 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -1288,6 +1288,17 @@ public final class VirtualDeviceManager { @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) default void onSecureWindowShown(int displayId, @NonNull ComponentName componentName, @NonNull UserHandle user) {} + + /** + * Called when a window with a secure surface is no longer shown on the device. + * + * @param displayId The display ID on which the window was shown before. + * + * @see Display#FLAG_SECURE + * @see WindowManager.LayoutParams#FLAG_SECURE + */ + @FlaggedApi(android.companion.virtualdevice.flags.Flags.FLAG_ACTIVITY_CONTROL_API) + default void onSecureWindowHidden(int displayId) {} } /** 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 4b9065bc7f72..6069e341521e 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -88,6 +88,9 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController /** Called when a secure window shows on the virtual display. */ void onSecureWindowShown(int displayId, @NonNull ActivityInfo activityInfo); + /** Called when a secure window is no longer shown on the virtual display. */ + void onSecureWindowHidden(int displayId); + /** Returns true when an intent should be intercepted */ boolean shouldInterceptIntent(@NonNull Intent intent); } @@ -123,6 +126,9 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController private boolean mIsMirrorDisplay = false; private final CountDownLatch mDisplayIdSetLatch = new CountDownLatch(1); + // Used for detecting changes in the window flags. + private int mCurrentWindowFlags = 0; + @NonNull @GuardedBy("mGenericWindowPolicyControllerLock") private final ArraySet<Integer> mRunningUids = new ArraySet<>(); @@ -371,12 +377,19 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags, int systemWindowFlags) { int displayId = waitAndGetDisplayId(); - // The callback is fired only when windowFlags are changed. To let VirtualDevice owner - // aware that the virtual display has a secure window on top. - if ((windowFlags & FLAG_SECURE) != 0 && displayId != INVALID_DISPLAY) { + if (displayId != INVALID_DISPLAY) { + // The callback is fired only when windowFlags are changed. To let VirtualDevice owner + // aware that the virtual display has a secure window on top. // Post callback on the main thread, so it doesn't block activity launching. - mHandler.post(() -> mActivityListener.onSecureWindowShown(displayId, activityInfo)); + if ((windowFlags & FLAG_SECURE) != 0 && (mCurrentWindowFlags & FLAG_SECURE) == 0) { + mHandler.post( + () -> mActivityListener.onSecureWindowShown(displayId, activityInfo)); + } + if ((windowFlags & FLAG_SECURE) == 0 && (mCurrentWindowFlags & FLAG_SECURE) != 0) { + mHandler.post(() -> mActivityListener.onSecureWindowHidden(displayId)); + } } + mCurrentWindowFlags = windowFlags; if (!CompatChanges.isChangeEnabled(ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE, activityInfo.packageName, 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 8b5b93e96494..a1d621d8dd1f 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -312,6 +312,17 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } } + @Override + public void onSecureWindowHidden(int displayId) { + if (android.companion.virtualdevice.flags.Flags.activityControlApi()) { + try { + mActivityListener.onSecureWindowHidden(displayId); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to call mActivityListener for display: " + displayId, e); + } + } + } + /** * Intercepts intent when matching any of the IntentFilter of any interceptor. Returns true * if the intent matches any filter notifying the DisplayPolicyController to abort the diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java index 1a593dd9baba..42b7f4bcda7b 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/GenericWindowPolicyControllerTest.java @@ -755,6 +755,7 @@ public class GenericWindowPolicyControllerTest { verify(mActivityListener, after(TIMEOUT_MILLIS).never()) .onSecureWindowShown(eq(DISPLAY_ID), eq(activityInfo)); + verify(mActivityListener, never()).onSecureWindowHidden(eq(DISPLAY_ID)); verify(mActivityListener, never()) .onActivityLaunchBlocked(eq(DISPLAY_ID), eq(activityInfo), any()); } @@ -776,6 +777,10 @@ public class GenericWindowPolicyControllerTest { .onSecureWindowShown(eq(DISPLAY_ID), eq(activityInfo)); verify(mActivityListener, after(TIMEOUT_MILLIS).never()) .onActivityLaunchBlocked(eq(DISPLAY_ID), eq(activityInfo), any()); + + assertThat(gwpc.keepActivityOnWindowFlagsChanged(activityInfo, 0, 0)).isTrue(); + + verify(mActivityListener, timeout(TIMEOUT_MILLIS)).onSecureWindowHidden(eq(DISPLAY_ID)); } @Test @@ -794,6 +799,7 @@ public class GenericWindowPolicyControllerTest { verify(mActivityListener, after(TIMEOUT_MILLIS).never()) .onSecureWindowShown(eq(DISPLAY_ID), eq(activityInfo)); + verify(mActivityListener, never()).onSecureWindowHidden(eq(DISPLAY_ID)); verify(mActivityListener, never()) .onActivityLaunchBlocked(eq(DISPLAY_ID), eq(activityInfo), any()); } |