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

Commit ccc0c90b authored by Mariia Sandrikova's avatar Mariia Sandrikova
Browse files

[6/n] Camera Compat: Orientation override for camera only

Adds OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA that acts as a modifier for the existing orientation overrides allowing to limit them to when the app is connected to the camera.

Fix: 226051012
Test: atest WmTests:LetterboxUiControllerTest
Change-Id: Iac7ea582dcdb996fc416576d886ab92c2d48c225
parent 46133ca9
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -1237,6 +1237,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
    @Overridable
    public static final long OVERRIDE_ANY_ORIENTATION = 265464455L;

    /**
     * When enabled, activates OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE,
     * OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR and OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT
     * only when an app is connected to the camera. See
     * com.android.server.wm.DisplayRotationCompatPolicy for more context.
     * @hide
     */
    @ChangeId
    @Disabled
    @Overridable
    public static final long OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA = 265456536L;

    /**
     * This override fixes display orientation to landscape natural orientation when a task is
     * fullscreen. While display rotation is fixed to landscape, the orientation requested by the
+24 −2
Original line number Diff line number Diff line
@@ -308,6 +308,10 @@ final class DisplayRotationCompatPolicy {
                && mDisplayContent.getDisplay().getType() == TYPE_INTERNAL;
    }

    boolean isActivityEligibleForOrientationOverride(@NonNull ActivityRecord activity) {
        return isTreatmentEnabledForDisplay() && isCameraActiveInFullscreen(activity);
    }

    /**
     * Whether camera compat treatment is applicable for the given activity.
     *
@@ -319,12 +323,16 @@ final class DisplayRotationCompatPolicy {
     * </ul>
     */
    boolean isTreatmentEnabledForActivity(@Nullable ActivityRecord activity) {
        return activity != null && !activity.inMultiWindowMode()
        return activity != null && isCameraActiveInFullscreen(activity)
                && activity.getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED
                // "locked" and "nosensor" values are often used by camera apps that can't
                // handle dynamic changes so we shouldn't force rotate them.
                && activity.getOverrideOrientation() != SCREEN_ORIENTATION_NOSENSOR
                && activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED
                && activity.getOverrideOrientation() != SCREEN_ORIENTATION_LOCKED;
    }

    private boolean isCameraActiveInFullscreen(@NonNull ActivityRecord activity) {
        return !activity.inMultiWindowMode()
                && mCameraIdPackageBiMap.containsPackageName(activity.packageName)
                && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
    }
@@ -369,6 +377,9 @@ final class DisplayRotationCompatPolicy {
        // Checking whether an activity in fullscreen rather than the task as this camera compat
        // treatment doesn't cover activity embedding.
        if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
            if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
                topActivity.recomputeConfiguration();
            }
            updateOrientationWithWmLock();
            return;
        }
@@ -423,6 +434,17 @@ final class DisplayRotationCompatPolicy {
        ProtoLog.v(WM_DEBUG_ORIENTATION,
                "Display id=%d is notified that Camera %s is closed, updating rotation.",
                mDisplayContent.mDisplayId, cameraId);
        ActivityRecord topActivity = mDisplayContent.topRunningActivity(
                /* considerKeyguardState= */ true);
        if (topActivity == null
                // Checking whether an activity in fullscreen rather than the task as this camera
                // compat treatment doesn't cover activity embedding.
                || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
            return;
        }
        if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
            topActivity.recomputeConfiguration();
        }
        updateOrientationWithWmLock();
    }

+6 −9
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ALLOW_IGNORE_ORIENTATION_REQUEST;
import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_CAMERA_COMPAT_TREATMENT;
import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY;

import android.annotation.IntDef;
@@ -309,6 +310,9 @@ final class LetterboxConfiguration {

        mIsDisplayRotationImmersiveAppCompatPolicyEnabled = mContext.getResources().getBoolean(
                R.bool.config_letterboxIsDisplayRotationImmersiveAppCompatPolicyEnabled);
        mDeviceConfig.updateFlagActiveStatus(
                /* isActive */ mIsCameraCompatTreatmentEnabled,
                /* key */ KEY_ENABLE_CAMERA_COMPAT_TREATMENT);
        mDeviceConfig.updateFlagActiveStatus(
                /* isActive */ mIsDisplayRotationImmersiveAppCompatPolicyEnabled,
                /* key */ KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY);
@@ -1118,15 +1122,8 @@ final class LetterboxConfiguration {

    /** Whether camera compatibility treatment is enabled. */
    boolean isCameraCompatTreatmentEnabled(boolean checkDeviceConfig) {
        return mIsCameraCompatTreatmentEnabled
                && (!checkDeviceConfig || isCameraCompatTreatmentAllowed());
    }

    // TODO(b/262977416): Cache a runtime flag and implement
    // DeviceConfig.OnPropertiesChangedListener
    private static boolean isCameraCompatTreatmentAllowed() {
        return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
                "enable_compat_camera_treatment", true);
        return mIsCameraCompatTreatmentEnabled && (!checkDeviceConfig
                || mDeviceConfig.getFlag(KEY_ENABLE_CAMERA_COMPAT_TREATMENT));
    }

    /** Whether camera compatibility refresh is enabled. */
+16 −0
Original line number Diff line number Diff line
@@ -33,6 +33,9 @@ import java.util.concurrent.Executor;
final class LetterboxConfigurationDeviceConfig
        implements DeviceConfig.OnPropertiesChangedListener {

    static final String KEY_ENABLE_CAMERA_COMPAT_TREATMENT = "enable_compat_camera_treatment";
    private static final boolean DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT = true;

    static final String KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY =
            "enable_display_rotation_immersive_app_compat_policy";
    private static final boolean DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY =
@@ -44,12 +47,19 @@ final class LetterboxConfigurationDeviceConfig

    @VisibleForTesting
    static final Map<String, Boolean> sKeyToDefaultValueMap = Map.of(
            KEY_ENABLE_CAMERA_COMPAT_TREATMENT,
            DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT,
            KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY,
            DEFAULT_VALUE_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY,
            KEY_ALLOW_IGNORE_ORIENTATION_REQUEST,
            DEFAULT_VALUE_ALLOW_IGNORE_ORIENTATION_REQUEST
    );

    // Whether camera compatibility treatment is enabled.
    // See DisplayRotationCompatPolicy for context.
    private boolean mIsCameraCompatTreatmentEnabled =
            DEFAULT_VALUE_ENABLE_CAMERA_COMPAT_TREATMENT;

    // Whether enabling rotation compat policy for immersive apps that prevents auto rotation
    // into non-optimal screen orientation while in fullscreen. This is needed because immersive
    // apps, such as games, are often not optimized for all orientations and can have a poor UX
@@ -101,6 +111,8 @@ final class LetterboxConfigurationDeviceConfig
     */
    boolean getFlag(String key) {
        switch (key) {
            case KEY_ENABLE_CAMERA_COMPAT_TREATMENT:
                return mIsCameraCompatTreatmentEnabled;
            case KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY:
                return mIsDisplayRotationImmersiveAppCompatPolicyEnabled;
            case KEY_ALLOW_IGNORE_ORIENTATION_REQUEST:
@@ -116,6 +128,10 @@ final class LetterboxConfigurationDeviceConfig
            throw new AssertionError("Haven't found default value for flag: " + key);
        }
        switch (key) {
            case KEY_ENABLE_CAMERA_COMPAT_TREATMENT:
                mIsCameraCompatTreatmentEnabled =
                        getDeviceConfig(key, defaultValue);
                break;
            case KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY:
                mIsDisplayRotationImmersiveAppCompatPolicyEnabled =
                        getDeviceConfig(key, defaultValue);
+17 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REF
import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR;
import static android.content.pm.ActivityInfo.OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT;
import static android.content.pm.ActivityInfo.OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION;
@@ -136,6 +137,8 @@ final class LetterboxUiController {
    private final boolean mIsOverrideToNosensorOrientationEnabled;
    // Corresponds to OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE
    private final boolean mIsOverrideToReverseLandscapeOrientationEnabled;
    // Corresponds to OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA
    private final boolean mIsOverrideOrientationOnlyForCameraEnabled;
    // Corresponds to OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION
    private final boolean mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled;

@@ -253,6 +256,8 @@ final class LetterboxUiController {
                isCompatChangeEnabled(OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE);
        mIsOverrideToNosensorOrientationEnabled =
                isCompatChangeEnabled(OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR);
        mIsOverrideOrientationOnlyForCameraEnabled =
                isCompatChangeEnabled(OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA);
        mIsOverrideUseDisplayLandscapeNaturalOrientationEnabled =
                isCompatChangeEnabled(OVERRIDE_USE_DISPLAY_LANDSCAPE_NATURAL_ORIENTATION);

@@ -410,6 +415,14 @@ final class LetterboxUiController {
            return candidate;
        }

        DisplayContent displayContent = mActivityRecord.mDisplayContent;
        if (mIsOverrideOrientationOnlyForCameraEnabled && displayContent != null
                && (displayContent.mDisplayRotationCompatPolicy == null
                        || !displayContent.mDisplayRotationCompatPolicy
                                .isActivityEligibleForOrientationOverride(mActivityRecord))) {
            return candidate;
        }

        if (mIsOverrideToReverseLandscapeOrientationEnabled
                && (isFixedOrientationLandscape(candidate) || mIsOverrideAnyOrientationEnabled)) {
            Slog.w(TAG, "Requested orientation  " + screenOrientationToString(candidate) + " for "
@@ -439,6 +452,10 @@ final class LetterboxUiController {
        return candidate;
    }

    boolean isOverrideOrientationOnlyForCameraEnabled() {
        return mIsOverrideOrientationOnlyForCameraEnabled;
    }

    /**
     * Whether activity is eligible for activity "refresh" after camera compat force rotation
     * treatment. See {@link DisplayRotationCompatPolicy} for context.
Loading