Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2d16883 authored by Mina Granic's avatar Mina Granic
Browse files

Limit letterboxing to CameraCompat in freeform.

DisplayRotationCompatPolicy should not change the
letterbox check as letterboxing is not a part of
that policy.

Flag: com.android.window.flags.enable_camera_compat_for_desktop_windowing
Fixes: 381183179
Test: atest WmTests:CameraCompatFreeformPolicyTests
Test: atest WmTests:ActivityRecordTests
Change-Id: Id736389316c9e1eed837a0f60d9428a48dac2e2b
parent a17d435d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -8491,7 +8491,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        final boolean isFixedOrientationLetterboxAllowed = !getLaunchedFromBubble()
                && (parentWindowingMode == WINDOWING_MODE_MULTI_WINDOW
                        || parentWindowingMode == WINDOWING_MODE_FULLSCREEN
                        || AppCompatCameraPolicy.shouldCameraCompatControlOrientation(this)
                        || AppCompatCameraPolicy.isFreeformLetterboxingForCameraAllowed(this)
                        // When starting to switch between PiP and fullscreen, the task is pinned
                        // and the activity is fullscreen. But only allow to apply letterbox if the
                        // activity is exiting PiP because an entered PiP should fill the task.
+11 −0
Original line number Diff line number Diff line
@@ -192,6 +192,17 @@ class AppCompatCameraPolicy {
                                .shouldCameraCompatControlOrientation(activity));
    }

    // TODO(b/369070416): have policies implement the same interface.
    static boolean isFreeformLetterboxingForCameraAllowed(@NonNull ActivityRecord activity) {
        final AppCompatCameraPolicy cameraPolicy = getAppCompatCameraPolicy(activity);
        if (cameraPolicy == null) {
            return false;
        }
        return cameraPolicy.mCameraCompatFreeformPolicy != null
                        && cameraPolicy.mCameraCompatFreeformPolicy
                                .isFreeformLetterboxingForCameraAllowed(activity);
    }

    // TODO(b/369070416): have policies implement the same interface.
    static boolean shouldCameraCompatControlAspectRatio(@NonNull ActivityRecord activity) {
        final AppCompatCameraPolicy cameraPolicy = getAppCompatCameraPolicy(activity);
+10 −0
Original line number Diff line number Diff line
@@ -205,6 +205,16 @@ final class CameraCompatFreeformPolicy implements CameraStateMonitor.CameraCompa
        }
    }

    /**
     * Returns true if letterboxing should be allowed for camera apps, even if otherwise it isn't.
     *
     * <p>Camera compat is currently the only use-case of letterboxing for desktop windowing.
     */
    boolean isFreeformLetterboxingForCameraAllowed(@NonNull ActivityRecord activity) {
        // Letterboxing is normally not allowed in desktop windowing.
        return isCameraRunningAndWindowingModeEligible(activity);
    }

    boolean shouldCameraCompatControlOrientation(@NonNull ActivityRecord activity) {
        return isCameraRunningAndWindowingModeEligible(activity);
    }
+100 −0
Original line number Diff line number Diff line
@@ -32,6 +32,8 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -124,6 +126,7 @@ import android.app.servertransaction.ClientTransactionItem;
import android.app.servertransaction.DestroyActivityItem;
import android.app.servertransaction.PauseActivityItem;
import android.app.servertransaction.WindowStateResizeItem;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -138,6 +141,7 @@ import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
import android.util.MutableBoolean;
@@ -159,9 +163,13 @@ import com.android.internal.R;
import com.android.server.wm.ActivityRecord.State;
import com.android.window.flags.Flags;

import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
@@ -183,6 +191,9 @@ import java.util.function.Consumer;
@RunWith(WindowTestRunner.class)
public class ActivityRecordTests extends WindowTestsBase {

    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();

    private final String mPackageName = getInstrumentation().getTargetContext().getPackageName();

    private static final int ORIENTATION_CONFIG_CHANGES =
@@ -717,6 +728,64 @@ public class ActivityRecordTests extends WindowTestsBase {
                .isLetterboxedForFixedOrientationAndAspectRatio());
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testOrientation_allowFixedOrientationForCameraCompatInFreeformWindowing() {
        final ActivityRecord activity = setupDisplayAndActivityForCameraCompat(
                /* isCameraRunning= */ true, WINDOWING_MODE_FREEFORM);

        // Task in landscape.
        assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
        // The app should be letterboxed.
        assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation);
        assertTrue(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
                .isLetterboxedForFixedOrientationAndAspectRatio());
    }

    @Test
    public void testOrientation_dontAllowFixedOrientationForCameraCompatFreeformIfNotEnabled() {
        final ActivityRecord activity = setupDisplayAndActivityForCameraCompat(
                /* isCameraRunning= */ true, WINDOWING_MODE_FREEFORM);

        // Task in landscape.
        assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
        // Activity is not letterboxed.
        assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
        assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
                .isLetterboxedForFixedOrientationAndAspectRatio());
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testOrientation_noFixedOrientationForCameraCompatFreeformIfCameraNotRunning() {
        final ActivityRecord activity = setupDisplayAndActivityForCameraCompat(
                /* isCameraRunning= */ false, WINDOWING_MODE_FREEFORM);

        // Task in landscape.
        assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
        // Activity is not letterboxed.
        assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
        assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
                .isLetterboxedForFixedOrientationAndAspectRatio());
    }

    @Test
    @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testOrientation_dontAllowFixedOrientationForCameraCompatFreeformIfInPip() {
        final ActivityRecord activity = setupDisplayAndActivityForCameraCompat(
                /* isCameraRunning= */ true, WINDOWING_MODE_PINNED);

        // Task in landscape.
        assertEquals(ORIENTATION_LANDSCAPE, activity.getTask().getConfiguration().orientation);
        // Activity is not letterboxed.
        assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation);
        assertFalse(activity.mAppCompatController.getAppCompatAspectRatioPolicy()
                .isLetterboxedForFixedOrientationAndAspectRatio());
    }

    @Test
    public void testShouldMakeActive_deferredResume() {
        final ActivityRecord activity = createActivityWithTask();
@@ -3686,6 +3755,37 @@ public class ActivityRecordTests extends WindowTestsBase {
        assertTrue(appWindow.mResizeReported);
    }

    private ActivityRecord setupDisplayAndActivityForCameraCompat(boolean isCameraRunning,
            int windowingMode) {
        doReturn(true).when(() -> DesktopModeHelper.canEnterDesktopMode(any()));
        // Create a new DisplayContent so that the flag values create the camera freeform policy.
        mDisplayContent = new TestDisplayContent.Builder(mAtm, mDisplayContent.getSurfaceWidth(),
                mDisplayContent.getSurfaceHeight()).build();
        final CameraStateMonitor cameraStateMonitor = mDisplayContent.mAppCompatCameraPolicy
                .mCameraStateMonitor;
        spyOn(cameraStateMonitor);
        doReturn(isCameraRunning).when(cameraStateMonitor).isCameraRunningForActivity(any());
        final TaskDisplayArea tda = mDisplayContent.getDefaultTaskDisplayArea();
        spyOn(tda);
        doReturn(true).when(tda).supportsNonResizableMultiWindow();
        final Task rootTask = new TaskBuilder(mSupervisor).setDisplay(mDisplayContent)
                .setWindowingMode(windowingMode).build();
        doReturn(mDisplayContent.getDisplayInfo())
                .when(mDisplayContent.mWmService.mDisplayManagerInternal).getDisplayInfo(anyInt());
        rootTask.setBounds(0, 0, 1000, 500);
        final ActivityRecord activity = new ActivityBuilder(mAtm)
                .setComponent(ComponentName.createRelative(mContext,
                        com.android.server.wm.ActivityRecordTests.class.getName()))
                .setParentTask(rootTask)
                .setCreateTask(true)
                .setOnTop(true)
                .setResizeMode(RESIZE_MODE_RESIZEABLE)
                .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT)
                .build();
        activity.mAppCompatController.getAppCompatSizeCompatModePolicy().clearSizeCompatMode();
        return activity;
    }

    private void assertHasStartingWindow(ActivityRecord atoken) {
        assertNotNull(atoken.mStartingSurface);
        assertNotNull(atoken.mStartingData);
+52 −0
Original line number Diff line number Diff line
@@ -202,6 +202,58 @@ public class CameraCompatFreeformPolicyTests extends WindowTestsBase {
        assertTrue(mCameraCompatFreeformPolicy.isCameraRunningAndWindowingModeEligible(mActivity));
    }

    @Test
    @DisableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testIsFreeformLetterboxingForCameraAllowed_featureDisabled_returnsFalse() {
        configureActivity(SCREEN_ORIENTATION_PORTRAIT);

        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);

        assertFalse(mCameraCompatFreeformPolicy.isFreeformLetterboxingForCameraAllowed(mActivity));
    }

    @Test
    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    public void testIsFreeformLetterboxingForCameraAllowed_overrideDisabled_returnsFalse() {
        configureActivity(SCREEN_ORIENTATION_PORTRAIT);

        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);

        assertFalse(mCameraCompatFreeformPolicy.isFreeformLetterboxingForCameraAllowed(mActivity));
    }

    @Test
    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testIsFreeformLetterboxingForCameraAllowed_cameraNotRunning_returnsFalse() {
        configureActivity(SCREEN_ORIENTATION_PORTRAIT);

        assertFalse(mCameraCompatFreeformPolicy.isFreeformLetterboxingForCameraAllowed(mActivity));
    }

    @Test
    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testIsFreeformLetterboxingForCameraAllowed_notFreeformWindowing_returnsFalse() {
        configureActivity(SCREEN_ORIENTATION_PORTRAIT, WINDOWING_MODE_FULLSCREEN);

        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);

        assertFalse(mCameraCompatFreeformPolicy.isFreeformLetterboxingForCameraAllowed(mActivity));
    }

    @Test
    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testIsFreeformLetterboxingForCameraAllowed_optInFreeformCameraRunning_true() {
        configureActivity(SCREEN_ORIENTATION_PORTRAIT);

        mCameraAvailabilityCallback.onCameraOpened(CAMERA_ID_1, TEST_PACKAGE_1);

        assertTrue(mCameraCompatFreeformPolicy.isFreeformLetterboxingForCameraAllowed(mActivity));
    }

    @Test
    @EnableFlags(FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})