[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
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -22,6 +22,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;
|
||||
@@ -576,6 +577,42 @@ public class LetterboxUiControllerTest extends WindowTestsBase {
|
||||
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT,
|
||||
OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
|
||||
public void testOverrideOrientationIfNeeded_whenCameraNotActive_returnsUnchanged() {
|
||||
doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled(anyBoolean());
|
||||
|
||||
// Recreate DisplayContent with DisplayRotationCompatPolicy
|
||||
mActivity = setUpActivityWithComponent();
|
||||
mController = new LetterboxUiController(mWm, mActivity);
|
||||
|
||||
spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
|
||||
doReturn(false).when(mDisplayContent.mDisplayRotationCompatPolicy)
|
||||
.isActivityEligibleForOrientationOverride(eq(mActivity));
|
||||
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnableCompatChanges({OVERRIDE_UNDEFINED_ORIENTATION_TO_PORTRAIT,
|
||||
OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
|
||||
public void testOverrideOrientationIfNeeded_whenCameraActive_returnsPortrait() {
|
||||
doReturn(true).when(mLetterboxConfiguration).isCameraCompatTreatmentEnabled(anyBoolean());
|
||||
|
||||
// Recreate DisplayContent with DisplayRotationCompatPolicy
|
||||
mActivity = setUpActivityWithComponent();
|
||||
mController = new LetterboxUiController(mWm, mActivity);
|
||||
|
||||
spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
|
||||
doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
|
||||
.isActivityEligibleForOrientationOverride(eq(mActivity));
|
||||
|
||||
assertEquals(mController.overrideOrientationIfNeeded(
|
||||
/* candidate */ SCREEN_ORIENTATION_UNSPECIFIED), SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
|
||||
// shouldUseDisplayLandscapeNaturalOrientation
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user