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

Commit 799faf13 authored by Mina Granic's avatar Mina Granic
Browse files

[1/n] Camera Compat Freeform: per-app controls for disabling the treatment.

Adds a way for OEMs to disable camera compat window resizing and camera adjustments using OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT.

Test: atest WmTests:LetterboxUiControllerTest
Fix: 314961188
Change-Id: I3ed591f426bc1b79b4531c5267d9711ae74939f6
parent 9c6c9980
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -1280,6 +1280,26 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
    public static final long OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE =
            264301586L; // buganizer id

    /**
     * Excludes the packages the override is applied to from the camera compatibility treatment
     * in free-form windowing mode for fixed-orientation apps.
     *
     * <p>In free-form windowing mode, the compatibility treatment emulates running on a portrait
     * device by letterboxing the app window and changing the camera characteristics to what apps
     * commonly expect in a portrait device: 90 and 270 degree sensor rotation for back and front
     * cameras, respectively, and setting display rotation to 0.
     *
     * <p>Use this flag to disable the compatibility treatment for apps that do not respond well to
     * the treatment.
     *
     * @hide
     */
    @ChangeId
    @Overridable
    @Disabled
    public static final long OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT =
            314961188L;

    /**
     * This change id forces the packages it is applied to sandbox {@link android.view.View} API to
     * an activity bounds for:
+37 −12
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
@@ -131,6 +132,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.LetterboxDetails;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
import com.android.window.flags.Flags;

import java.io.PrintWriter;
import java.util.ArrayList;
@@ -194,7 +196,8 @@ final class LetterboxUiController {
    private final boolean mIsOverrideCameraCompatDisableRefreshEnabled;
    // Corresponds to OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE
    private final boolean mIsOverrideCameraCompatEnableRefreshViaPauseEnabled;

    // Corresponds to OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT
    private final boolean mIsOverrideCameraCompatDisableFreeformWindowingTreatmentEnabled;
    // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION
    private final boolean mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled;
    // Corresponds to OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED
@@ -321,15 +324,15 @@ final class LetterboxUiController {
                        PROPERTY_COMPAT_ENABLE_FAKE_FOCUS);
        mBooleanPropertyCameraCompatAllowForceRotation =
                readComponentProperty(packageManager, mActivityRecord.packageName,
                        () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
                        mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
                        PROPERTY_CAMERA_COMPAT_ALLOW_FORCE_ROTATION);
        mBooleanPropertyCameraCompatAllowRefresh =
                readComponentProperty(packageManager, mActivityRecord.packageName,
                        () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
                        mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
                        PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH);
        mBooleanPropertyCameraCompatEnableRefreshViaPause =
                readComponentProperty(packageManager, mActivityRecord.packageName,
                        () -> mLetterboxConfiguration.isCameraCompatTreatmentEnabled(),
                        mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
                        PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);

        mBooleanPropertyAllowOrientationOverride =
@@ -351,11 +354,11 @@ final class LetterboxUiController {

        mBooleanPropertyAllowUserAspectRatioOverride =
                readComponentProperty(packageManager, mActivityRecord.packageName,
                        () -> mLetterboxConfiguration.isUserAppAspectRatioSettingsEnabled(),
                        mLetterboxConfiguration::isUserAppAspectRatioSettingsEnabled,
                        PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE);
        mBooleanPropertyAllowUserAspectRatioFullscreenOverride =
                readComponentProperty(packageManager, mActivityRecord.packageName,
                        () -> mLetterboxConfiguration.isUserAppAspectRatioFullscreenEnabled(),
                        mLetterboxConfiguration::isUserAppAspectRatioFullscreenEnabled,
                        PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE);

        mIsOverrideAnyOrientationEnabled = isCompatChangeEnabled(OVERRIDE_ANY_ORIENTATION);
@@ -380,6 +383,8 @@ final class LetterboxUiController {
                isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH);
        mIsOverrideCameraCompatEnableRefreshViaPauseEnabled =
                isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE);
        mIsOverrideCameraCompatDisableFreeformWindowingTreatmentEnabled =
                isCompatChangeEnabled(OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT);

        mIsOverrideEnableCompatIgnoreRequestedOrientationEnabled =
                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION);
@@ -759,8 +764,7 @@ final class LetterboxUiController {
     */
    boolean shouldRefreshActivityForCameraCompat() {
        return shouldEnableWithOptOutOverrideAndProperty(
                /* gatingCondition */ () -> mLetterboxConfiguration
                        .isCameraCompatTreatmentEnabled(),
                /* gatingCondition */ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
                mIsOverrideCameraCompatDisableRefreshEnabled,
                mBooleanPropertyCameraCompatAllowRefresh);
    }
@@ -781,8 +785,7 @@ final class LetterboxUiController {
     */
    boolean shouldRefreshActivityViaPauseForCameraCompat() {
        return shouldEnableWithOverrideAndProperty(
                /* gatingCondition */ () -> mLetterboxConfiguration
                        .isCameraCompatTreatmentEnabled(),
                /* gatingCondition */ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
                mIsOverrideCameraCompatEnableRefreshViaPauseEnabled,
                mBooleanPropertyCameraCompatEnableRefreshViaPause);
    }
@@ -800,12 +803,34 @@ final class LetterboxUiController {
     */
    boolean shouldForceRotateForCameraCompat() {
        return shouldEnableWithOptOutOverrideAndProperty(
                /* gatingCondition */ () -> mLetterboxConfiguration
                        .isCameraCompatTreatmentEnabled(),
                /* gatingCondition */ mLetterboxConfiguration::isCameraCompatTreatmentEnabled,
                mIsOverrideCameraCompatDisableForceRotationEnabled,
                mBooleanPropertyCameraCompatAllowForceRotation);
    }

    /**
     * Whether activity is eligible for camera compatibility free-form treatment.
     *
     * <p>The treatment is applied to a fixed-orientation camera activity in free-form windowing
     * mode. The treatment letterboxes or pillarboxes the activity to the expected orientation and
     * provides changes to the camera and display orientation signals to match those expected on a
     * portrait device in that orientation (for example, on a standard phone).
     *
     * <p>The treatment is enabled when the following conditions are met:
     * <ul>
     * <li>Property gating the camera compatibility free-form treatment is enabled.
     * <li>Activity isn't opted out by the device manufacturer with override or by the app
     * developers with the component property.
     * </ul>
     */
    boolean shouldApplyFreeformTreatmentForCameraCompat() {
        return shouldEnableWithOptOutOverrideAndProperty(
                /* gatingCondition */ ()-> Flags.cameraCompatForFreeform(),
                mIsOverrideCameraCompatDisableFreeformWindowingTreatmentEnabled,
                // TODO(b/328616176): add a manifest override for developers.
                null);
    }

    private boolean isCameraCompatTreatmentActive() {
        DisplayContent displayContent = mActivityRecord.mDisplayContent;
        if (displayContent == null) {
+50 −6
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.FORCE_RESIZE_APP;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_ANY_ORIENTATION_TO_USER;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FORCE_ROTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS;
@@ -63,6 +64,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.LetterboxUiController.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
import static com.android.server.wm.LetterboxUiController.SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS;
import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -81,6 +83,7 @@ import android.content.pm.PackageManager.Property;
import android.content.res.Resources;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.platform.test.flag.junit.SetFlagsRule;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.RoundedCorner;
@@ -122,6 +125,8 @@ public class LetterboxUiControllerTest extends WindowTestsBase {

    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();
    @Rule
    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    private ActivityRecord mActivity;
    private Task mTask;
@@ -466,6 +471,44 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
        assertTrue(mController.shouldForceRotateForCameraCompat());
    }

    // shouldApplyFreeformTreatmentForCameraCompat

    @Test
    public void testShouldApplyCameraCompatFreeformTreatment_flagIsDisabled_returnsFalse() {
        mSetFlagsRule.disableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);

        assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
    }

    @Test
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testShouldApplyCameraCompatFreeformTreatment_overrideEnabled_returnsFalse() {
        mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);

        assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
    }

    @Test
    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT})
    public void testShouldApplyCameraCompatFreeformTreatment_disabledByOverride_returnsFalse()
            throws Exception {
        mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);

        mController = new LetterboxUiController(mWm, mActivity);

        assertFalse(mController.shouldApplyFreeformTreatmentForCameraCompat());
    }

    @Test
    public void testShouldApplyCameraCompatFreeformTreatment_notDisabledByOverride_returnsTrue()
            throws Exception {
        mSetFlagsRule.enableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM);

        mController = new LetterboxUiController(mWm, mActivity);

        assertTrue(mController.shouldApplyFreeformTreatmentForCameraCompat());
    }

    @Test
    public void testGetCropBoundsIfNeeded_handleCropForTransparentActivityBasedOnOpaqueBounds() {
        final InsetsSource taskbar = new InsetsSource(/*id=*/ 0,
@@ -859,6 +902,7 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
        assertEquals(SCREEN_ORIENTATION_USER, mController.overrideOrientationIfNeeded(
                /* candidate */ SCREEN_ORIENTATION_UNSPECIFIED));
    }

    @Test
    public void testOverrideOrientationIfNeeded_respectOrientationRequestOverUserFullScreen() {
        spyOn(mController);