diff --git a/core/java/android/window/DisplayWindowPolicyController.java b/core/java/android/window/DisplayWindowPolicyController.java index 3359a41369d7d..1270d87e3a044 100644 --- a/core/java/android/window/DisplayWindowPolicyController.java +++ b/core/java/android/window/DisplayWindowPolicyController.java @@ -17,12 +17,14 @@ package android.window; import android.annotation.NonNull; +import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.util.ArraySet; import java.io.PrintWriter; import java.util.List; +import java.util.Set; /** * Abstract class to control the policies of the windows that can be displayed on the virtual @@ -45,6 +47,22 @@ public abstract class DisplayWindowPolicyController { */ private int mSystemWindowFlags; + /** + * The set of windowing mode that are supported in this display. + * @see android.app.WindowConfiguration.WindowingMode + */ + private final Set mSupportedWindowingModes = new ArraySet<>(); + + /** + * A controller to control the policies of the windows that can be displayed on the virtual + * display. + */ + public DisplayWindowPolicyController() { + synchronized (mSupportedWindowingModes) { + mSupportedWindowingModes.add(WindowConfiguration.WINDOWING_MODE_FULLSCREEN); + } + } + /** * Returns {@code true} if the given window flags contain the flags that we're interested in. */ @@ -62,9 +80,34 @@ public abstract class DisplayWindowPolicyController { } /** - * Returns {@code true} if the given activities can be displayed on this virtual display. + * Returns {@code true} if the given windowing mode is supported in this display. */ - public abstract boolean canContainActivities(@NonNull List activities); + public final boolean isWindowingModeSupported( + @WindowConfiguration.WindowingMode int windowingMode) { + synchronized (mSupportedWindowingModes) { + return mSupportedWindowingModes.contains(windowingMode); + } + } + + /** + * Sets the windowing modes are supported in this display. + * + * @param supportedWindowingModes The set of + * {@link android.app.WindowConfiguration.WindowingMode}. + */ + public final void setSupportedWindowingModes(Set supportedWindowingModes) { + synchronized (mSupportedWindowingModes) { + mSupportedWindowingModes.clear(); + mSupportedWindowingModes.addAll(supportedWindowingModes); + } + } + + /** + * Returns {@code true} if the given activities can be displayed on this virtual display and + * the windowing mode is supported. + */ + public abstract boolean canContainActivities(@NonNull List activities, + @WindowConfiguration.WindowingMode int windowingMode); /** * Called when an Activity window is layouted with the new changes where contains the 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 b991ba87eef46..3a26c46116290 100644 --- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java +++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java @@ -22,6 +22,7 @@ import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTE import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.WindowConfiguration; import android.app.compat.CompatChanges; import android.companion.virtual.VirtualDeviceManager.ActivityListener; import android.companion.virtual.VirtualDeviceParams; @@ -119,6 +120,7 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController @ActivityPolicy int defaultActivityPolicy, @NonNull ActivityListener activityListener, @NonNull Consumer activityBlockedCallback) { + super(); mAllowedUsers = allowedUsers; mAllowedActivities = new ArraySet<>(allowedActivities); mBlockedActivities = new ArraySet<>(blockedActivities); @@ -134,7 +136,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController } @Override - public boolean canContainActivities(@NonNull List activities) { + public boolean canContainActivities(@NonNull List activities, + @WindowConfiguration.WindowingMode int windowingMode) { + if (!isWindowingModeSupported(windowingMode)) { + return false; + } // Can't display all the activities if any of them don't want to be displayed. final int activityCount = activities.size(); for (int i = 0; i < activityCount; i++) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 677babea4dd43..5c5aff2a66d16 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2914,7 +2914,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A */ boolean supportsPictureInPicture() { return mAtmService.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined() - && info.supportsPictureInPicture(); + && info.supportsPictureInPicture() + && (mDisplayContent != null && mDisplayContent.mDwpcHelper.isWindowingModeSupported( + WINDOWING_MODE_PINNED)); } /** diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index 64f426187fd23..eb5ca9c2f43b4 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -402,7 +402,8 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { activities.add(r.info); }); } - if (!displayContent.mDwpcHelper.canContainActivities(activities)) { + if (!displayContent.mDwpcHelper.canContainActivities(activities, + displayContent.getWindowingMode())) { return false; } } diff --git a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java index 60d2a5da9286e..27d46ecfb91a1 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java +++ b/services/core/java/com/android/server/wm/DisplayWindowPolicyControllerHelper.java @@ -18,6 +18,7 @@ package com.android.server.wm; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.WindowConfiguration; import android.content.pm.ActivityInfo; import android.os.UserHandle; import android.util.ArraySet; @@ -63,13 +64,14 @@ class DisplayWindowPolicyControllerHelper { } /** - * @see DisplayWindowPolicyController#canContainActivities(List) + * @see DisplayWindowPolicyController#canContainActivities(List, int) */ - public boolean canContainActivities(@NonNull List activities) { + public boolean canContainActivities(@NonNull List activities, + @WindowConfiguration.WindowingMode int windowingMode) { if (mDisplayWindowPolicyController == null) { return true; } - return mDisplayWindowPolicyController.canContainActivities(activities); + return mDisplayWindowPolicyController.canContainActivities(activities, windowingMode); } /** @@ -126,6 +128,17 @@ class DisplayWindowPolicyControllerHelper { } } + /** + * @see DisplayWindowPolicyController#isWindowingModeSupported(int) + */ + public final boolean isWindowingModeSupported( + @WindowConfiguration.WindowingMode int windowingMode) { + if (mDisplayWindowPolicyController == null) { + return true; + } + return mDisplayWindowPolicyController.isWindowingModeSupported(windowingMode); + } + void dump(String prefix, PrintWriter pw) { if (mDisplayWindowPolicyController != null) { pw.println(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 40ab8eb70c049..6d248950b1f9e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -2184,11 +2184,17 @@ public class ActivityRecordTests extends WindowTestsBase { @Test public void testSupportsPictureInPicture() { + final Task task = new TaskBuilder(mSupervisor) + .setDisplay(mDisplayContent).build(); final ActivityRecord activity = new ActivityBuilder(mAtm) - .setCreateTask(true) + .setTask(task) .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE) .build(); + spyOn(mDisplayContent); + spyOn(mDisplayContent.mDwpcHelper); + doReturn(true).when(mDisplayContent.mDwpcHelper).isWindowingModeSupported( + WINDOWING_MODE_PINNED); // Device not supports PIP mAtm.mSupportsPictureInPicture = false; @@ -2201,6 +2207,15 @@ public class ActivityRecordTests extends WindowTestsBase { // Activity not supports PIP activity.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE; assertFalse(activity.supportsPictureInPicture()); + + // Activity supports PIP + activity.info.flags |= FLAG_SUPPORTS_PICTURE_IN_PICTURE; + assertTrue(activity.supportsPictureInPicture()); + + // Display not supports PIP + doReturn(false).when(mDisplayContent.mDwpcHelper).isWindowingModeSupported( + WINDOWING_MODE_PINNED); + assertFalse(activity.supportsPictureInPicture()); } @Test diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java index 6e11d8cf23e17..f9689990c5e84 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowPolicyControllerHelperTests.java @@ -16,13 +16,18 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; +import android.app.WindowConfiguration; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.os.UserHandle; @@ -37,6 +42,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.List; +import java.util.Set; /** * Tests for the {@link DisplayWindowPolicyControllerHelper} class. @@ -113,6 +119,39 @@ public class DisplayWindowPolicyControllerHelperTests extends WindowTestsBase { return activity; } + @Test + public void testIsWindowingModeSupported_noController_returnTrueForAnyWindowingMode() { + doReturn(null).when(mWm.mDisplayManagerInternal) + .getDisplayWindowPolicyController(anyInt()); + mSecondaryDisplay = createNewDisplay(); + assertFalse(mSecondaryDisplay.mDwpcHelper.hasController()); + + assertTrue(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED)); + assertTrue( + mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_FULLSCREEN)); + } + + @Test + public void testIsWindowingModeSupported_withoutSettingSupportedMode_returnFalse() { + assertFalse(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED)); + } + + @Test + public void testIsWindowingModeSupported_withoutSupportedMode_defaultSupportFullScreen() { + assertTrue( + mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_FULLSCREEN)); + } + + @Test + public void testIsWindowingModeSupported_setPinnedMode_returnTrue() { + Set supportedWindowingMode = new ArraySet<>(); + supportedWindowingMode.add(WINDOWING_MODE_PINNED); + + mDwpc.setSupportedWindowingModes(supportedWindowingMode); + + assertTrue(mSecondaryDisplay.mDwpcHelper.isWindowingModeSupported(WINDOWING_MODE_PINNED)); + } + private class TestDisplayWindowPolicyController extends DisplayWindowPolicyController { ComponentName mTopActivity = null; @@ -120,7 +159,8 @@ public class DisplayWindowPolicyControllerHelperTests extends WindowTestsBase { ArraySet mRunningUids = new ArraySet<>(); @Override - public boolean canContainActivities(@NonNull List activities) { + public boolean canContainActivities(@NonNull List activities, + @WindowConfiguration.WindowingMode int windowingMode) { return false; }