Merge "[15/n] Improved AppCompat camera classes dependencies" into main
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index efe07dc..b0f92e8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6535,9 +6535,7 @@
             // and the token could be null.
             return;
         }
-        if (r.mDisplayContent.mActivityRefresher != null) {
-            r.mDisplayContent.mActivityRefresher.onActivityRefreshed(r);
-        }
+        r.mDisplayContent.mAppCompatCameraPolicy.onActivityRefreshed(r);
     }
 
     static void splashScreenAttachedLocked(IBinder token) {
@@ -8194,7 +8192,7 @@
     }
 
     void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) {
-        if (mAppCompatController.getAppCompatOrientationOverrides()
+        if (mAppCompatController.getOrientationPolicy()
                 .shouldIgnoreRequestedOrientation(requestedOrientation)) {
             return;
         }
@@ -10030,16 +10028,6 @@
         return updateReportedConfigurationAndSend();
     }
 
-    /**
-     * @return {@code true} if the Camera is active for the current activity
-     */
-    boolean isCameraActive() {
-        return mDisplayContent != null
-                && mDisplayContent.getDisplayRotationCompatPolicy() != null
-                && mDisplayContent.getDisplayRotationCompatPolicy()
-                    .isCameraActive(this, /* mustBeFullscreen */ true);
-    }
-
     boolean updateReportedConfigurationAndSend() {
         if (isConfigurationDispatchPaused()) {
             Slog.wtf(TAG, "trying to update reported(client) config while dispatch is paused");
@@ -10187,11 +10175,10 @@
 
     private void notifyActivityRefresherAboutConfigurationChange(
             Configuration newConfig, Configuration lastReportedConfig) {
-        if (mDisplayContent.mActivityRefresher == null
-                || !shouldBeResumed(/* activeActivity */ null)) {
+        if (!shouldBeResumed(/* activeActivity */ null)) {
             return;
         }
-        mDisplayContent.mActivityRefresher.onActivityConfigurationChanging(
+        mDisplayContent.mAppCompatCameraPolicy.onActivityConfigurationChanging(
                 this, newConfig, lastReportedConfig);
     }
 
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
index c0e5005..0d108e1 100644
--- a/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatCameraOverrides.java
@@ -97,8 +97,7 @@
      * </ul>
      */
     boolean shouldOverrideMinAspectRatioForCamera() {
-        return mActivityRecord.isCameraActive()
-                && mAllowMinAspectRatioOverrideOptProp
+        return isCameraActive() && mAllowMinAspectRatioOverrideOptProp
                 .shouldEnableWithOptInOverrideAndOptOutProperty(
                         isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA));
     }
@@ -174,6 +173,15 @@
     }
 
     /**
+     * @return {@code true} if the Camera is active for the current activity
+     */
+    boolean isCameraActive() {
+        return mActivityRecord.mDisplayContent != null
+                && mActivityRecord.mDisplayContent.mAppCompatCameraPolicy
+                    .isCameraActive(mActivityRecord, /* mustBeFullscreen */ true);
+    }
+
+    /**
      * @return {@code true} if the configuration needs to be recomputed after a camera state update.
      */
     boolean shouldRecomputeConfigurationForCameraCompat() {
diff --git a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
index ee523a2..53729a2 100644
--- a/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatCameraPolicy.java
@@ -16,34 +16,158 @@
 
 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 android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo.ScreenOrientation;
+import android.content.res.Configuration;
+import android.widget.Toast;
+
+import com.android.window.flags.Flags;
 
 /**
- * Encapsulate the app compat logic related to camera.
+ * Encapsulate policy logic related to app compat display rotation.
  */
 class AppCompatCameraPolicy {
 
-    private static final String TAG = TAG_WITH_CLASS_NAME
-            ? "AppCompatCameraPolicy" : TAG_ATM;
+    @Nullable
+    private final CameraStateMonitor mCameraStateMonitor;
+    @Nullable
+    private final ActivityRefresher mActivityRefresher;
+    @Nullable
+    final DisplayRotationCompatPolicy mDisplayRotationCompatPolicy;
+    @Nullable
+    final CameraCompatFreeformPolicy mCameraCompatFreeformPolicy;
 
-    @NonNull
-    private final ActivityRecord mActivityRecord;
-
-    @NonNull
-    private final AppCompatCameraOverrides mAppCompatCameraOverrides;
-
-    AppCompatCameraPolicy(@NonNull ActivityRecord activityRecord,
-            @NonNull AppCompatCameraOverrides appCompatCameraOverrides) {
-        mActivityRecord = activityRecord;
-        mAppCompatCameraOverrides = appCompatCameraOverrides;
-    }
-
-    void recomputeConfigurationForCameraCompatIfNeeded() {
-        if (mAppCompatCameraOverrides.shouldRecomputeConfigurationForCameraCompat()) {
-            mActivityRecord.recomputeConfiguration();
+    AppCompatCameraPolicy(@NonNull WindowManagerService wmService,
+            @NonNull DisplayContent displayContent) {
+        // Not checking DeviceConfig value here to allow enabling via DeviceConfig
+        // without the need to restart the device.
+        final boolean needsDisplayRotationCompatPolicy =
+                wmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabledAtBuildTime();
+        final boolean needsCameraCompatFreeformPolicy = Flags.cameraCompatForFreeform()
+                && DesktopModeLaunchParamsModifier.canEnterDesktopMode(wmService.mContext);
+        if (needsDisplayRotationCompatPolicy || needsCameraCompatFreeformPolicy) {
+            mCameraStateMonitor = new CameraStateMonitor(displayContent, wmService.mH);
+            mActivityRefresher = new ActivityRefresher(wmService, wmService.mH);
+            mDisplayRotationCompatPolicy =
+                    needsDisplayRotationCompatPolicy ? new DisplayRotationCompatPolicy(
+                            displayContent, mCameraStateMonitor, mActivityRefresher) : null;
+            mCameraCompatFreeformPolicy =
+                    needsCameraCompatFreeformPolicy ? new CameraCompatFreeformPolicy(displayContent,
+                            mCameraStateMonitor, mActivityRefresher) : null;
+        } else {
+            mDisplayRotationCompatPolicy = null;
+            mCameraCompatFreeformPolicy = null;
+            mCameraStateMonitor = null;
+            mActivityRefresher = null;
         }
     }
+
+    void onActivityRefreshed(@NonNull ActivityRecord activity) {
+        if (mActivityRefresher != null) {
+            mActivityRefresher.onActivityRefreshed(activity);
+        }
+    }
+
+    /**
+     * "Refreshes" activity by going through "stopped -> resumed" or "paused -> resumed" cycle.
+     * This allows to clear cached values in apps (e.g. display or camera rotation) that influence
+     * camera preview and can lead to sideways or stretching issues persisting even after force
+     * rotation.
+     */
+    void onActivityConfigurationChanging(@NonNull ActivityRecord activity,
+            @NonNull Configuration newConfig, @NonNull Configuration lastReportedConfig) {
+        if (mActivityRefresher != null) {
+            mActivityRefresher.onActivityConfigurationChanging(activity, newConfig,
+                    lastReportedConfig);
+        }
+    }
+
+    /**
+     * Notifies that animation in {@link ScreenRotationAnimation} has finished.
+     *
+     * <p>This class uses this signal as a trigger for notifying the user about forced rotation
+     * reason with the {@link Toast}.
+     */
+    void onScreenRotationAnimationFinished() {
+        if (mDisplayRotationCompatPolicy != null) {
+            mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
+        }
+    }
+
+    boolean isActivityEligibleForOrientationOverride(@NonNull ActivityRecord activity) {
+        if (mDisplayRotationCompatPolicy != null) {
+            return mDisplayRotationCompatPolicy.isActivityEligibleForOrientationOverride(activity);
+        }
+        return false;
+    }
+
+    /**
+     * Whether camera compat treatment is applicable for the given activity.
+     *
+     * <p>Conditions that need to be met:
+     * <ul>
+     *     <li>Camera is active for the package.
+     *     <li>The activity is in fullscreen
+     *     <li>The activity has fixed orientation but not "locked" or "nosensor" one.
+     * </ul>
+     */
+    boolean isTreatmentEnabledForActivity(@Nullable ActivityRecord activity) {
+        if (mDisplayRotationCompatPolicy != null) {
+            return mDisplayRotationCompatPolicy.isTreatmentEnabledForActivity(activity);
+        }
+        return false;
+    }
+
+    void start() {
+        if (mCameraCompatFreeformPolicy != null) {
+            mCameraCompatFreeformPolicy.start();
+        }
+        if (mCameraStateMonitor != null) {
+            mCameraStateMonitor.startListeningToCameraState();
+        }
+    }
+
+    void dispose() {
+        if (mDisplayRotationCompatPolicy != null) {
+            mDisplayRotationCompatPolicy.dispose();
+        }
+        if (mCameraCompatFreeformPolicy != null) {
+            mCameraCompatFreeformPolicy.dispose();
+        }
+        if (mCameraStateMonitor != null) {
+            mCameraStateMonitor.dispose();
+        }
+    }
+
+    boolean hasDisplayRotationCompatPolicy() {
+        return mDisplayRotationCompatPolicy != null;
+    }
+
+    boolean hasCameraCompatFreeformPolicy() {
+        return mCameraCompatFreeformPolicy != null;
+    }
+
+    @ScreenOrientation
+    int getOrientation() {
+        return mDisplayRotationCompatPolicy != null
+                ? mDisplayRotationCompatPolicy.getOrientation()
+                : SCREEN_ORIENTATION_UNSPECIFIED;
+    }
+
+    boolean isCameraActive(@NonNull ActivityRecord activity, boolean mustBeFullscreen) {
+        return mDisplayRotationCompatPolicy != null
+                && mDisplayRotationCompatPolicy.isCameraActive(activity, mustBeFullscreen);
+    }
+
+    @Nullable
+    String getSummaryForDisplayRotationHistoryRecord() {
+        if (mDisplayRotationCompatPolicy != null) {
+            return mDisplayRotationCompatPolicy.getSummaryForDisplayRotationHistoryRecord();
+        }
+        return null;
+    }
+
 }
diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java
index d8c0c17..16d3787 100644
--- a/services/core/java/com/android/server/wm/AppCompatController.java
+++ b/services/core/java/com/android/server/wm/AppCompatController.java
@@ -16,6 +16,7 @@
 package com.android.server.wm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.pm.PackageManager;
 
 import com.android.server.wm.utils.OptPropFactory;
@@ -26,16 +27,17 @@
 class AppCompatController {
 
     @NonNull
+    private final ActivityRecord mActivityRecord;
+    @NonNull
     private final TransparentPolicy mTransparentPolicy;
     @NonNull
     private final AppCompatOrientationPolicy mOrientationPolicy;
     @NonNull
     private final AppCompatOverrides mAppCompatOverrides;
-    @NonNull
-    private final AppCompatCameraPolicy mAppCompatCameraPolicy;
 
     AppCompatController(@NonNull WindowManagerService wmService,
                         @NonNull ActivityRecord activityRecord) {
+        mActivityRecord = activityRecord;
         final PackageManager packageManager = wmService.mContext.getPackageManager();
         final OptPropFactory optPropBuilder = new OptPropFactory(packageManager,
                 activityRecord.packageName);
@@ -49,8 +51,6 @@
                 mAppCompatOverrides, tmpController::shouldApplyUserFullscreenOverride,
                 tmpController::shouldApplyUserMinAspectRatioOverride,
                 tmpController::isSystemOverrideToFullscreenEnabled);
-        mAppCompatCameraPolicy = new AppCompatCameraPolicy(activityRecord,
-                mAppCompatOverrides.getAppCompatCameraOverrides());
     }
 
     @NonNull
@@ -64,11 +64,6 @@
     }
 
     @NonNull
-    AppCompatCameraPolicy getAppCompatCameraPolicy() {
-        return mAppCompatCameraPolicy;
-    }
-
-    @NonNull
     AppCompatOverrides getAppCompatOverrides() {
         return mAppCompatOverrides;
     }
@@ -82,4 +77,12 @@
     AppCompatCameraOverrides getAppCompatCameraOverrides() {
         return mAppCompatOverrides.getAppCompatCameraOverrides();
     }
+
+    @Nullable
+    AppCompatCameraPolicy getAppCompatCameraPolicy() {
+        if (mActivityRecord.mDisplayContent != null) {
+            return mActivityRecord.mDisplayContent.mAppCompatCameraPolicy;
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
index b0fdbb5..155e246 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java
@@ -22,7 +22,6 @@
 import static android.content.pm.ActivityInfo.OVERRIDE_LANDSCAPE_ORIENTATION_TO_REVERSE_LANDSCAPE;
 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.screenOrientationToString;
 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
 import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 
@@ -31,8 +30,6 @@
 import static com.android.server.wm.AppCompatUtils.asLazy;
 
 import android.annotation.NonNull;
-import android.content.pm.ActivityInfo;
-import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.wm.utils.OptPropFactory;
@@ -51,6 +48,8 @@
 
     @NonNull
     private final ActivityRecord mActivityRecord;
+    @NonNull
+    private final AppCompatCameraOverrides mAppCompatCameraOverrides;
 
     @NonNull
     private final OptPropFactory.OptProp mIgnoreRequestedOrientationOptProp;
@@ -62,8 +61,10 @@
 
     AppCompatOrientationOverrides(@NonNull ActivityRecord activityRecord,
             @NonNull LetterboxConfiguration letterboxConfiguration,
-            @NonNull OptPropFactory optPropBuilder) {
+            @NonNull OptPropFactory optPropBuilder,
+            @NonNull AppCompatCameraOverrides appCompatCameraOverrides) {
         mActivityRecord = activityRecord;
+        mAppCompatCameraOverrides = appCompatCameraOverrides;
         mOrientationOverridesState = new OrientationOverridesState(mActivityRecord,
                 System::currentTimeMillis);
         final BooleanSupplier isPolicyForIgnoringRequestedOrientationEnabled = asLazy(
@@ -76,59 +77,9 @@
                 isPolicyForIgnoringRequestedOrientationEnabled);
     }
 
-    /**
-     * Whether should ignore app requested orientation in response to an app
-     * calling {@link android.app.Activity#setRequestedOrientation}.
-     *
-     * <p>This is needed to avoid getting into {@link android.app.Activity#setRequestedOrientation}
-     * loop when {@link DisplayContent#getIgnoreOrientationRequest} is enabled or device has
-     * landscape natural orientation which app developers don't expect. For example, the loop can
-     * look like this:
-     * <ol>
-     *     <li>App sets default orientation to "unspecified" at runtime
-     *     <li>App requests to "portrait" after checking some condition (e.g. display rotation).
-     *     <li>(2) leads to fullscreen -> letterboxed bounds change and activity relaunch because
-     *     app can't handle the corresponding config changes.
-     *     <li>Loop goes back to (1)
-     * </ol>
-     *
-     * <p>This treatment is enabled when the following conditions are met:
-     * <ul>
-     *     <li>Flag gating the treatment is enabled
-     *     <li>Opt-out component property isn't enabled
-     *     <li>Opt-in component property or per-app override are enabled
-     *     <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation}
-     *     call from an app or camera compat force rotation treatment is active for the activity.
-     *     <li>Orientation request loop detected and is not letterboxed for fixed orientation
-     * </ul>
-     */
-    boolean shouldIgnoreRequestedOrientation(
-            @ActivityInfo.ScreenOrientation int requestedOrientation) {
-        if (mIgnoreRequestedOrientationOptProp.shouldEnableWithOverrideAndProperty(
-                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION))) {
-            if (mOrientationOverridesState.mIsRelaunchingAfterRequestedOrientationChanged) {
-                Slog.w(TAG, "Ignoring orientation update to "
-                        + screenOrientationToString(requestedOrientation)
-                        + " due to relaunching after setRequestedOrientation for "
-                        + mActivityRecord);
-                return true;
-            }
-            if (isCameraCompatTreatmentActive()) {
-                Slog.w(TAG, "Ignoring orientation update to "
-                        + screenOrientationToString(requestedOrientation)
-                        + " due to camera compat treatment for " + mActivityRecord);
-                return true;
-            }
-        }
-
-        if (shouldIgnoreOrientationRequestLoop()) {
-            Slog.w(TAG, "Ignoring orientation update to "
-                    + screenOrientationToString(requestedOrientation)
-                    + " as orientation request loop was detected for "
-                    + mActivityRecord);
-            return true;
-        }
-        return false;
+    boolean shouldEnableIgnoreOrientationRequest() {
+        return mIgnoreRequestedOrientationOptProp.shouldEnableWithOverrideAndProperty(
+                isCompatChangeEnabled(OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION));
     }
 
     /**
@@ -183,20 +134,6 @@
         return mActivityRecord.info.isChangeEnabled(overrideChangeId);
     }
 
-    /**
-     * @return {@code true} if the App Compat Camera Policy is active for the current activity.
-     */
-    // TODO(b/346253439): Remove after defining dependency with Camera capabilities.
-    private boolean isCameraCompatTreatmentActive() {
-        DisplayContent displayContent = mActivityRecord.mDisplayContent;
-        if (displayContent == null) {
-            return false;
-        }
-        return displayContent.mDisplayRotationCompatPolicy != null
-                && displayContent.mDisplayRotationCompatPolicy
-                .isTreatmentEnabledForActivity(mActivityRecord);
-    }
-
     static class OrientationOverridesState {
         // Corresponds to OVERRIDE_UNDEFINED_ORIENTATION_TO_NOSENSOR
         final boolean mIsOverrideToNosensorOrientationEnabled;
diff --git a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
index 960ef5a..69ba59b 100644
--- a/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatOrientationPolicy.java
@@ -46,7 +46,6 @@
 
     @NonNull
     private final AppCompatOverrides mAppCompatOverrides;
-
     @NonNull
     private final BooleanSupplier mShouldApplyUserFullscreenOverride;
     @NonNull
@@ -78,7 +77,7 @@
                 // often results in sideways or stretched previews. As the camera compat treatment
                 // targets fixed-orientation activities, overriding the orientation disables the
                 // treatment.
-                && !mActivityRecord.isCameraActive()) {
+                && !mAppCompatOverrides.getAppCompatCameraOverrides().isCameraActive()) {
             Slog.v(TAG, "Requested orientation " + screenOrientationToString(candidate)
                     + " for " + mActivityRecord + " is overridden to "
                     + screenOrientationToString(SCREEN_ORIENTATION_USER)
@@ -103,11 +102,11 @@
             return candidate;
         }
 
-        if (displayContent != null && mAppCompatOverrides.getAppCompatCameraOverrides()
-                .isOverrideOrientationOnlyForCameraEnabled()
-                    && (displayContent.mDisplayRotationCompatPolicy == null
-                    || !displayContent.mDisplayRotationCompatPolicy
-                        .isActivityEligibleForOrientationOverride(mActivityRecord))) {
+        if (displayContent != null
+                && mAppCompatOverrides.getAppCompatCameraOverrides()
+                    .isOverrideOrientationOnlyForCameraEnabled()
+                && !displayContent.mAppCompatCameraPolicy
+                    .isActivityEligibleForOrientationOverride(mActivityRecord)) {
             return candidate;
         }
 
@@ -120,7 +119,7 @@
                 // often results in sideways or stretched previews. As the camera compat treatment
                 // targets fixed-orientation activities, overriding the orientation disables the
                 // treatment.
-                && !mActivityRecord.isCameraActive()) {
+                && !mAppCompatOverrides.getAppCompatCameraOverrides().isCameraActive()) {
             Slog.v(TAG, "Requested orientation  " + screenOrientationToString(candidate)
                     + " for " + mActivityRecord + " is overridden to "
                     + screenOrientationToString(SCREEN_ORIENTATION_USER));
@@ -161,4 +160,62 @@
         return candidate;
     }
 
+    /**
+     * Whether should ignore app requested orientation in response to an app
+     * calling {@link android.app.Activity#setRequestedOrientation}.
+     *
+     * <p>This is needed to avoid getting into {@link android.app.Activity#setRequestedOrientation}
+     * loop when {@link DisplayContent#getIgnoreOrientationRequest} is enabled or device has
+     * landscape natural orientation which app developers don't expect. For example, the loop can
+     * look like this:
+     * <ol>
+     *     <li>App sets default orientation to "unspecified" at runtime
+     *     <li>App requests to "portrait" after checking some condition (e.g. display rotation).
+     *     <li>(2) leads to fullscreen -> letterboxed bounds change and activity relaunch because
+     *     app can't handle the corresponding config changes.
+     *     <li>Loop goes back to (1)
+     * </ol>
+     *
+     * <p>This treatment is enabled when the following conditions are met:
+     * <ul>
+     *     <li>Flag gating the treatment is enabled
+     *     <li>Opt-out component property isn't enabled
+     *     <li>Opt-in component property or per-app override are enabled
+     *     <li>Activity is relaunched after {@link android.app.Activity#setRequestedOrientation}
+     *     call from an app or camera compat force rotation treatment is active for the activity.
+     *     <li>Orientation request loop detected and is not letterboxed for fixed orientation
+     * </ul>
+     */
+    boolean shouldIgnoreRequestedOrientation(
+            @ActivityInfo.ScreenOrientation int requestedOrientation) {
+        final AppCompatOrientationOverrides orientationOverrides =
+                mAppCompatOverrides.getAppCompatOrientationOverrides();
+        if (orientationOverrides.shouldEnableIgnoreOrientationRequest()) {
+            if (orientationOverrides.getIsRelaunchingAfterRequestedOrientationChanged()) {
+                Slog.w(TAG, "Ignoring orientation update to "
+                        + screenOrientationToString(requestedOrientation)
+                        + " due to relaunching after setRequestedOrientation for "
+                        + mActivityRecord);
+                return true;
+            }
+            final AppCompatCameraPolicy cameraPolicy = mActivityRecord.mAppCompatController
+                    .getAppCompatCameraPolicy();
+            if (cameraPolicy != null
+                    && cameraPolicy.isTreatmentEnabledForActivity(mActivityRecord)) {
+                Slog.w(TAG, "Ignoring orientation update to "
+                        + screenOrientationToString(requestedOrientation)
+                        + " due to camera compat treatment for " + mActivityRecord);
+                return true;
+            }
+        }
+        if (orientationOverrides.shouldIgnoreOrientationRequestLoop()) {
+            Slog.w(TAG, "Ignoring orientation update to "
+                    + screenOrientationToString(requestedOrientation)
+                    + " as orientation request loop was detected for "
+                    + mActivityRecord);
+            return true;
+        }
+        return false;
+    }
+
 }
diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java
index c20da7c..94c6ba9 100644
--- a/services/core/java/com/android/server/wm/AppCompatOverrides.java
+++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java
@@ -79,10 +79,10 @@
         mLetterboxConfiguration = letterboxConfiguration;
         mActivityRecord = activityRecord;
 
-        mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(mActivityRecord,
-                mLetterboxConfiguration, optPropBuilder);
         mAppCompatCameraOverrides = new AppCompatCameraOverrides(mActivityRecord,
                 mLetterboxConfiguration, optPropBuilder);
+        mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(mActivityRecord,
+                mLetterboxConfiguration, optPropBuilder, mAppCompatCameraOverrides);
 
         mFakeFocusOptProp = optPropBuilder.create(PROPERTY_COMPAT_ENABLE_FAKE_FOCUS,
                 mLetterboxConfiguration::isCompatFakeFocusEnabled);
@@ -113,19 +113,6 @@
                 mLetterboxConfiguration::isUserAppAspectRatioFullscreenEnabled);
     }
 
-    /**
-     * @return {@code true} if the App Compat Camera Policy is active for the current activity.
-     */
-    boolean isCameraCompatTreatmentActive() {
-        final DisplayContent displayContent = mActivityRecord.mDisplayContent;
-        if (displayContent == null) {
-            return false;
-        }
-        return displayContent.mDisplayRotationCompatPolicy != null
-                && displayContent.mDisplayRotationCompatPolicy
-                    .isTreatmentEnabledForActivity(mActivityRecord);
-    }
-
     @NonNull
     AppCompatOrientationOverrides getAppCompatOrientationOverrides() {
         return mAppCompatOrientationOverrides;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b5b9377..a8aa0ba 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -263,7 +263,6 @@
 import com.android.server.wm.utils.RegionUtils;
 import com.android.server.wm.utils.RotationCache;
 import com.android.server.wm.utils.WmDisplayCutout;
-import com.android.window.flags.Flags;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -475,14 +474,8 @@
     private final DisplayPolicy mDisplayPolicy;
     private final DisplayRotation mDisplayRotation;
 
-    @Nullable
-    final DisplayRotationCompatPolicy mDisplayRotationCompatPolicy;
-    @Nullable
-    final CameraCompatFreeformPolicy mCameraCompatFreeformPolicy;
-    @Nullable
-    final CameraStateMonitor mCameraStateMonitor;
-    @Nullable
-    final ActivityRefresher mActivityRefresher;
+    @NonNull
+    AppCompatCameraPolicy mAppCompatCameraPolicy;
 
     DisplayFrames mDisplayFrames;
     final DisplayUpdater mDisplayUpdater;
@@ -1191,6 +1184,7 @@
 
         mDeviceStateController = deviceStateController;
 
+        mAppCompatCameraPolicy = new AppCompatCameraPolicy(mWmService, this);
         mDisplayPolicy = new DisplayPolicy(mWmService, this);
         mDisplayRotation = new DisplayRotation(mWmService, this, mDisplayInfo.address,
                 mDeviceStateController, root.getDisplayRotationCoordinator());
@@ -1231,40 +1225,6 @@
         onDisplayChanged(this);
         updateDisplayAreaOrganizers();
 
-        // Not checking DeviceConfig value here to allow enabling via DeviceConfig
-        // without the need to restart the device.
-        final boolean shouldCreateDisplayRotationCompatPolicy =
-                mWmService.mLetterboxConfiguration.isCameraCompatTreatmentEnabledAtBuildTime();
-        final boolean shouldCreateCameraCompatFreeformPolicy = Flags.cameraCompatForFreeform()
-                && DesktopModeLaunchParamsModifier.canEnterDesktopMode(mWmService.mContext);
-        if (shouldCreateDisplayRotationCompatPolicy || shouldCreateCameraCompatFreeformPolicy) {
-            mCameraStateMonitor = new CameraStateMonitor(this, mWmService.mH);
-            mActivityRefresher = new ActivityRefresher(mWmService, mWmService.mH);
-            if (shouldCreateDisplayRotationCompatPolicy) {
-                mDisplayRotationCompatPolicy = new DisplayRotationCompatPolicy(this,
-                        mCameraStateMonitor, mActivityRefresher);
-                mDisplayRotationCompatPolicy.start();
-            } else {
-                mDisplayRotationCompatPolicy = null;
-            }
-
-            if (shouldCreateCameraCompatFreeformPolicy) {
-                mCameraCompatFreeformPolicy = new CameraCompatFreeformPolicy(this,
-                        mCameraStateMonitor, mActivityRefresher);
-                mCameraCompatFreeformPolicy.start();
-            } else {
-                mCameraCompatFreeformPolicy = null;
-            }
-
-            mCameraStateMonitor.startListeningToCameraState();
-        } else {
-            // These are to satisfy the `final` check.
-            mCameraStateMonitor = null;
-            mActivityRefresher = null;
-            mDisplayRotationCompatPolicy = null;
-            mCameraCompatFreeformPolicy = null;
-        }
-
         mRotationReversionController = new DisplayRotationReversionController(this);
 
         mInputMonitor = new InputMonitor(mWmService, this);
@@ -1280,6 +1240,7 @@
                 R.bool.config_defaultInTouchMode);
         mWmService.mInputManager.setInTouchMode(mInTouchMode, mWmService.MY_PID, mWmService.MY_UID,
                 /* hasPermission= */ true, mDisplayId);
+        mAppCompatCameraPolicy.start();
     }
 
     private void beginHoldScreenUpdate() {
@@ -1314,15 +1275,6 @@
         }
     }
 
-    /**
-     * @return The {@link DisplayRotationCompatPolicy} for this DisplayContent
-     */
-    // TODO(b/335387481) Allow access to DisplayRotationCompatPolicy only with getters
-    @Nullable
-    DisplayRotationCompatPolicy getDisplayRotationCompatPolicy() {
-        return mDisplayRotationCompatPolicy;
-    }
-
     @Override
     void migrateToNewSurfaceControl(Transaction t) {
         t.remove(mSurfaceControl);
@@ -2889,12 +2841,10 @@
             }
         }
 
-        if (mDisplayRotationCompatPolicy != null) {
-            int compatOrientation = mDisplayRotationCompatPolicy.getOrientation();
-            if (compatOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
-                mLastOrientationSource = null;
-                return compatOrientation;
-            }
+        final int compatOrientation = mAppCompatCameraPolicy.getOrientation();
+        if (compatOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
+            mLastOrientationSource = null;
+            return compatOrientation;
         }
 
         final int orientation = super.getOrientation();
@@ -3364,17 +3314,7 @@
         getPendingTransaction().apply();
         mWmService.mWindowPlacerLocked.requestTraversal();
 
-        if (mDisplayRotationCompatPolicy != null) {
-            mDisplayRotationCompatPolicy.dispose();
-        }
-
-        if (mCameraCompatFreeformPolicy != null) {
-            mCameraCompatFreeformPolicy.dispose();
-        }
-
-        if (mCameraStateMonitor != null) {
-            mCameraStateMonitor.dispose();
-        }
+        mAppCompatCameraPolicy.dispose();
     }
 
     /** Returns true if a removal action is still being deferred. */
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index f3ccc3b..c67928a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -2294,10 +2294,8 @@
                     mInHalfFoldTransition = false;
                     mDeviceState = DeviceStateController.DeviceState.UNKNOWN;
                 }
-                mDisplayRotationCompatPolicySummary = dc.mDisplayRotationCompatPolicy == null
-                        ? null
-                        : dc.mDisplayRotationCompatPolicy
-                                .getSummaryForDisplayRotationHistoryRecord();
+                mDisplayRotationCompatPolicySummary = dc.mAppCompatCameraPolicy
+                        .getSummaryForDisplayRotationHistoryRecord();
                 mRotationReversionSlots =
                         dr.mDisplayContent.getRotationReversionController().getSlotsCopy();
             }
diff --git a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
index 3d71e95..9998e1a 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationCompatPolicy.java
@@ -299,8 +299,7 @@
         // Checking whether an activity in fullscreen rather than the task as this camera
         // compat treatment doesn't cover activity embedding.
         if (cameraActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
-            cameraActivity.mAppCompatController
-                    .getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
+            recomputeConfigurationForCameraCompatIfNeeded(cameraActivity);
             mDisplayContent.updateOrientation();
             return true;
         }
@@ -367,8 +366,7 @@
                 || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
             return true;
         }
-        topActivity.mAppCompatController
-                .getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
+        recomputeConfigurationForCameraCompatIfNeeded(topActivity);
         mDisplayContent.updateOrientation();
         return true;
     }
@@ -383,4 +381,12 @@
         }
         return mActivityRefresher.isActivityRefreshing(topActivity);
     }
+
+    private void recomputeConfigurationForCameraCompatIfNeeded(
+            @NonNull ActivityRecord activityRecord) {
+        if (activityRecord.mAppCompatController.getAppCompatCameraOverrides()
+                .shouldRecomputeConfigurationForCameraCompat()) {
+            activityRecord.recomputeConfiguration();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
index f94b8c4..b955738 100644
--- a/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
+++ b/services/core/java/com/android/server/wm/DisplayRotationReversionController.java
@@ -61,7 +61,7 @@
     }
 
     boolean isRotationReversionEnabled() {
-        return mDisplayContent.mDisplayRotationCompatPolicy != null
+        return mDisplayContent.mAppCompatCameraPolicy.hasDisplayRotationCompatPolicy()
                 || mDisplayContent.getDisplayRotation().mFoldController != null
                 || mDisplayContent.getIgnoreOrientationRequest();
     }
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index e924fb6..a3550bc 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -462,12 +462,16 @@
         final boolean isTabletopMode = isDisplayFullScreenAndInPosture(/* isTabletop */ true);
         final boolean isLandscape = isFixedOrientationLandscape(
                 mActivityRecord.getOverrideOrientation());
-
+        final AppCompatCameraOverrides appCompatCameraOverrides =
+                mActivityRecord.mAppCompatController.getAppCompatCameraOverrides();
+        final AppCompatCameraPolicy cameraPolicy =
+                mActivityRecord.mAppCompatController.getAppCompatCameraPolicy();
+        final boolean isCameraCompatTreatmentActive = cameraPolicy != null
+                && cameraPolicy.isTreatmentEnabledForActivity(mActivityRecord);
         // Don't resize to split screen size when in book mode if letterbox position is centered
         return (isBookMode && isNotCenteredHorizontally || isTabletopMode && isLandscape)
-                    || mActivityRecord.mAppCompatController.getAppCompatCameraOverrides()
-                            .isCameraCompatSplitScreenAspectRatioAllowed()
-                                && getAppCompatOverrides().isCameraCompatTreatmentActive();
+                    || (appCompatCameraOverrides.isCameraCompatSplitScreenAspectRatioAllowed()
+                    && isCameraCompatTreatmentActive);
     }
 
     private float getDefaultMinAspectRatioForUnresizableApps() {
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 3eb3218..31fda77 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -815,10 +815,8 @@
                 if (mDisplayContent.getRotationAnimation() == ScreenRotationAnimation.this) {
                     // It also invokes kill().
                     mDisplayContent.setRotationAnimation(null);
-                    if (mDisplayContent.mDisplayRotationCompatPolicy != null) {
-                        mDisplayContent.mDisplayRotationCompatPolicy
-                                .onScreenRotationAnimationFinished();
-                    }
+                    mDisplayContent.mAppCompatCameraPolicy
+                            .onScreenRotationAnimationFinished();
                 } else {
                     kill();
                 }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index f839ed6..47af6fc 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -105,8 +105,8 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
 import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.ProtoLogGroup;
 import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.ProtoLogGroup;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
@@ -1443,11 +1443,11 @@
                 asyncRotationController.onTransitionFinished();
             }
             dc.onTransitionFinished();
-            if (hasParticipatedDisplay && dc.mDisplayRotationCompatPolicy != null) {
+            if (hasParticipatedDisplay) {
                 final ChangeInfo changeInfo = mChanges.get(dc);
                 if (changeInfo != null
                         && changeInfo.mRotation != dc.getWindowConfiguration().getRotation()) {
-                    dc.mDisplayRotationCompatPolicy.onScreenRotationAnimationFinished();
+                    dc.mAppCompatCameraPolicy.onScreenRotationAnimationFinished();
                 }
             }
             if (mTransientLaunches != null) {
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 2e9726f..eb8825c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -116,7 +116,6 @@
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.when;
 
 import android.app.ActivityOptions;
 import android.app.AppOpsManager;
@@ -3508,23 +3507,6 @@
     }
 
     @Test
-    public void testIsCameraActive() {
-        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
-        final DisplayRotationCompatPolicy displayRotationCompatPolicy = mock(
-                DisplayRotationCompatPolicy.class);
-        when(mDisplayContent.getDisplayRotationCompatPolicy()).thenReturn(
-                displayRotationCompatPolicy);
-
-        when(displayRotationCompatPolicy.isCameraActive(any(ActivityRecord.class),
-                anyBoolean())).thenReturn(false);
-        assertFalse(app.mActivityRecord.isCameraActive());
-
-        when(displayRotationCompatPolicy.isCameraActive(any(ActivityRecord.class),
-                anyBoolean())).thenReturn(true);
-        assertTrue(app.mActivityRecord.isCameraActive());
-    }
-
-    @Test
     public void testUpdateCameraCompatStateFromUser_clickedOnDismiss() throws RemoteException {
         final ActivityRecord activity = createActivityWithTask();
         // Mock a flag being enabled.
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
index 467050e..f79cdc1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -69,6 +69,7 @@
 
     private final int mDisplayWidth;
     private final int mDisplayHeight;
+    private DisplayContent mDisplayContent;
 
     AppCompatActivityRobot(@NonNull WindowManagerService wm,
             @NonNull ActivityTaskManagerService atm, @NonNull ActivityTaskSupervisor supervisor,
@@ -79,6 +80,7 @@
         mDisplayHeight = displayHeight;
         mActivityStack = new TestComponentStack<>();
         mTaskStack = new TestComponentStack<>();
+        createNewDisplay();
     }
 
     AppCompatActivityRobot(@NonNull WindowManagerService wm,
@@ -87,13 +89,19 @@
     }
 
     void createActivityWithComponent() {
-        createActivityWithComponentInNewTask(/* inNewTask */ mTaskStack.isEmpty());
+        createActivityWithComponentInNewTask(/* inNewTask */ mTaskStack.isEmpty(),
+                /* inNewDisplay */ false);
     }
 
     void createActivityWithComponentInNewTask() {
-        createActivityWithComponentInNewTask(/* inNewTask */ true);
+        createActivityWithComponentInNewTask(/* inNewTask */ true, /* inNewDisplay */ false);
     }
 
+    void createActivityWithComponentInNewTaskAndDisplay() {
+        createActivityWithComponentInNewTask(/* inNewTask */ true, /* inNewDisplay */ true);
+    }
+
+
     void configureTopActivity(float minAspect, float maxAspect, int screenOrientation,
             boolean isUnresizable) {
         prepareLimitedBounds(mActivityStack.top(), minAspect, maxAspect, screenOrientation,
@@ -110,12 +118,22 @@
                 /* isUnresizable */ true);
     }
 
+    void activateCameraInPolicy(boolean isCameraActive) {
+        doReturn(isCameraActive).when(mDisplayContent.mAppCompatCameraPolicy)
+                .isCameraActive(any(ActivityRecord.class), anyBoolean());
+    }
+
     @NonNull
     ActivityRecord top() {
         return mActivityStack.top();
     }
 
     @NonNull
+    DisplayContent displayContent() {
+        return mDisplayContent;
+    }
+
+    @NonNull
     ActivityRecord getFromTop(int fromTop) {
         return mActivityStack.getFromTop(fromTop);
     }
@@ -130,7 +148,7 @@
     }
 
     void enableTreatmentForTopActivity(boolean enabled) {
-        doReturn(enabled).when(getTopDisplayRotationCompatPolicy())
+        doReturn(enabled).when(mDisplayContent.mAppCompatCameraPolicy)
                 .isTreatmentEnabledForActivity(eq(mActivityStack.top()));
     }
 
@@ -164,7 +182,7 @@
     }
 
     void setIgnoreOrientationRequest(boolean enabled) {
-        mActivityStack.top().mDisplayContent.setIgnoreOrientationRequest(enabled);
+        mDisplayContent.setIgnoreOrientationRequest(enabled);
     }
 
     void setTopActivityAsEmbedded(boolean embedded) {
@@ -179,20 +197,22 @@
         mActivityStack.applyTo(/* fromTop */ fromTop, ActivityRecord::removeImmediately);
     }
 
+    void createNewDisplay() {
+        mDisplayContent = new TestDisplayContent.Builder(mAtm, mDisplayWidth, mDisplayHeight)
+                .build();
+        spyOnAppCompatCameraPolicy();
+    }
+
     void createNewTask() {
-        final DisplayContent displayContent = new TestDisplayContent
-                .Builder(mAtm, mDisplayWidth, mDisplayHeight).build();
         final Task newTask = new WindowTestsBase.TaskBuilder(mSupervisor)
-                .setDisplay(displayContent).build();
+                .setDisplay(mDisplayContent).build();
         mTaskStack.push(newTask);
     }
 
     void createNewTaskWithBaseActivity() {
-        final DisplayContent displayContent = new TestDisplayContent
-                .Builder(mAtm, mDisplayWidth, mDisplayHeight).build();
         final Task newTask = new WindowTestsBase.TaskBuilder(mSupervisor)
                 .setCreateActivity(true)
-                .setDisplay(displayContent).build();
+                .setDisplay(mDisplayContent).build();
         mTaskStack.push(newTask);
         pushActivity(newTask.getTopNonFinishingActivity());
     }
@@ -319,7 +339,10 @@
         pushActivity(newActivity);
     }
 
-    private void createActivityWithComponentInNewTask(boolean inNewTask) {
+    private void createActivityWithComponentInNewTask(boolean inNewTask, boolean inNewDisplay) {
+        if (inNewDisplay) {
+            createNewDisplay();
+        }
         if (inNewTask) {
             createNewTask();
         }
@@ -369,7 +392,8 @@
     }
 
     private DisplayRotationCompatPolicy getTopDisplayRotationCompatPolicy() {
-        return mActivityStack.top().mDisplayContent.mDisplayRotationCompatPolicy;
+        return mActivityStack.top().mDisplayContent
+                .mAppCompatCameraPolicy.mDisplayRotationCompatPolicy;
     }
 
     // We add the activity to the stack and spyOn() on its properties.
@@ -377,10 +401,16 @@
         mActivityStack.push(activity);
         spyOn(activity);
         spyOn(activity.mAppCompatController.getTransparentPolicy());
-        if (activity.mDisplayContent != null
-                && activity.mDisplayContent.mDisplayRotationCompatPolicy != null) {
-            spyOn(activity.mDisplayContent.mDisplayRotationCompatPolicy);
-        }
         spyOn(activity.mLetterboxUiController);
     }
+
+    private void spyOnAppCompatCameraPolicy() {
+        spyOn(mDisplayContent.mAppCompatCameraPolicy);
+        if (mDisplayContent.mAppCompatCameraPolicy.hasDisplayRotationCompatPolicy()) {
+            spyOn(mDisplayContent.mAppCompatCameraPolicy.mDisplayRotationCompatPolicy);
+        }
+        if (mDisplayContent.mAppCompatCameraPolicy.hasCameraCompatFreeformPolicy()) {
+            spyOn(mDisplayContent.mAppCompatCameraPolicy.mCameraCompatFreeformPolicy);
+        }
+    }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
index 9263b4f..2d94b34 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraOverridesTest.java
@@ -26,7 +26,6 @@
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH;
 import static android.view.WindowManager.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
 
@@ -264,14 +263,29 @@
     public void testShouldRecomputeConfigurationForCameraCompat() {
         runTestScenario((robot) -> {
             robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
-            robot.activity().createActivityWithComponentInNewTask();
-            robot.activateCamera(true);
-            robot.activity().setShouldCreateCompatDisplayInsets(false);
+            robot.applyOnActivity((a) -> {
+                a.createActivityWithComponentInNewTask();
+                a.activateCameraInPolicy(true);
+                a.setShouldCreateCompatDisplayInsets(false);
+            });
 
             robot.checkShouldApplyFreeformTreatmentForCameraCompat(true);
         });
     }
 
+    @Test
+    public void testIsCameraActive() {
+        runTestScenario((robot) -> {
+            robot.applyOnActivity((a) -> {
+                a.createActivityWithComponent();
+                a.activateCameraInPolicy(/* isCameraActive */ false);
+                robot.checkIsCameraActive(/* active */ false);
+                a.activateCameraInPolicy(/* isCameraActive */ true);
+                robot.checkIsCameraActive(/* active */ true);
+            });
+        });
+    }
+
     /**
      * Runs a test scenario providing a Robot.
      */
@@ -289,10 +303,6 @@
             super(wm, atm, supervisor);
         }
 
-        void activateCamera(boolean isCameraActive) {
-            doReturn(isCameraActive).when(activity().top()).isCameraActive();
-        }
-
         void checkShouldRefreshActivityForCameraCompat(boolean expected) {
             Assert.assertEquals(getAppCompatCameraOverrides()
                     .shouldRefreshActivityForCameraCompat(), expected);
@@ -313,6 +323,10 @@
                     .shouldApplyFreeformTreatmentForCameraCompat(), expected);
         }
 
+        void checkIsCameraActive(boolean active) {
+            Assert.assertEquals(getAppCompatCameraOverrides().isCameraActive(), active);
+        }
+
         private AppCompatCameraOverrides getAppCompatCameraOverrides() {
             return activity().top().mAppCompatController.getAppCompatCameraOverrides();
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
index 4116313..006b370 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatCameraPolicyTest.java
@@ -16,23 +16,20 @@
 
 package com.android.server.wm;
 
-import static android.content.pm.ActivityInfo.OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA;
-import static android.content.pm.ActivityInfo.OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA;
-
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.window.flags.Flags.FLAG_CAMERA_COMPAT_FOR_FREEFORM;
 
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
+import static org.mockito.ArgumentMatchers.any;
 
 import android.compat.testing.PlatformCompatChangeRule;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.annotation.NonNull;
 
-import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
-import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
-
+import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TestRule;
@@ -54,96 +51,128 @@
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
 
     @Test
-    @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
-    public void testRecomputeConfigurationForCameraCompatIfNeeded_allDisabledNoRecompute() {
+    public void testDisplayRotationCompatPolicy_presentWhenEnabled() {
         runTestScenario((robot) -> {
-            robot.activity().createActivityWithComponent();
-            robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
-            robot.activateCamera(/* isCameraActive */ false);
-
-            robot.recomputeConfigurationForCameraCompatIfNeeded();
-            robot.checkRecomputeConfigurationInvoked(/* invoked */ false);
-
+            robot.conf().enableCameraCompatTreatmentAtBuildTime(true);
+            robot.activity().createActivityWithComponentInNewTaskAndDisplay();
+            robot.checkTopActivityHasDisplayRotationCompatPolicy(true);
         });
     }
 
     @Test
-    @EnableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
-    public void testRecomputeConfigurationForCameraCompatIfNeeded_cameraEnabledRecompute() {
+    public void testDisplayRotationCompatPolicy_notPresentWhenDisabled() {
         runTestScenario((robot) -> {
-            robot.activity().createActivityWithComponent();
-            robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
-            robot.activateCamera(/* isCameraActive */ false);
-
-            robot.recomputeConfigurationForCameraCompatIfNeeded();
-            robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+            robot.conf().enableCameraCompatTreatmentAtBuildTime(false);
+            robot.activity().createActivityWithComponentInNewTaskAndDisplay();
+            robot.checkTopActivityHasDisplayRotationCompatPolicy(false);
         });
     }
 
     @Test
-    @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
-    public void testRecomputeConfigurationForCameraSplitScreenCompatIfNeeded_recompute() {
+    @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+    public void testCameraCompatFreeformPolicy_presentWhenEnabledAndDW() {
         runTestScenario((robot) -> {
-            robot.activity().createActivityWithComponent();
-            robot.conf().enableCameraCompatSplitScreenAspectRatio(true);
-            robot.activateCamera(/* isCameraActive */ false);
-
-            robot.recomputeConfigurationForCameraCompatIfNeeded();
-            robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+            robot.allowEnterDesktopMode(true);
+            robot.activity().createActivityWithComponentInNewTaskAndDisplay();
+            robot.checkTopActivityHasCameraCompatFreeformPolicy(true);
         });
     }
 
     @Test
-    @DisableCompatChanges({OVERRIDE_ORIENTATION_ONLY_FOR_CAMERA})
-    @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
-    public void testRecomputeConfigurationForCameraSplitScreenCompatIfNeededWithCamera_recompute() {
+    @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+    public void testCameraCompatFreeformPolicy_notPresentWhenNoDW() {
         runTestScenario((robot) -> {
-            robot.activity().createActivityWithComponent();
-            robot.conf().enableCameraCompatSplitScreenAspectRatio(false);
-            robot.activateCamera(/* isCameraActive */ true);
-
-            robot.recomputeConfigurationForCameraCompatIfNeeded();
-            robot.checkRecomputeConfigurationInvoked(/* invoked */ true);
+            robot.allowEnterDesktopMode(false);
+            robot.activity().createActivityWithComponentInNewTaskAndDisplay();
+            robot.checkTopActivityHasCameraCompatFreeformPolicy(false);
         });
     }
 
-    void runTestScenario(@NonNull Consumer<CameraPolicyRobotTest> consumer) {
+    @Test
+    @DisableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+    public void testCameraCompatFreeformPolicy_notPresentWhenNoFlag() {
+        runTestScenario((robot) -> {
+            robot.allowEnterDesktopMode(true);
+            robot.activity().createActivityWithComponentInNewTaskAndDisplay();
+            robot.checkTopActivityHasCameraCompatFreeformPolicy(false);
+        });
+    }
+
+    @Test
+    @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
+    public void testCameraCompatFreeformPolicy_notPresentWhenNoFlagAndNoDW() {
+        runTestScenario((robot) -> {
+            robot.allowEnterDesktopMode(false);
+            robot.activity().createActivityWithComponentInNewTaskAndDisplay();
+            robot.checkTopActivityHasCameraCompatFreeformPolicy(false);
+        });
+    }
+
+    /**
+     * Runs a test scenario providing a Robot.
+     */
+    void runTestScenario(@NonNull Consumer<DisplayRotationPolicyRobotTest> consumer) {
         spyOn(mWm.mLetterboxConfiguration);
-        final CameraPolicyRobotTest robot = new CameraPolicyRobotTest(mWm, mAtm, mSupervisor);
+        final DisplayRotationPolicyRobotTest robot =
+                new DisplayRotationPolicyRobotTest(mWm, mAtm, mSupervisor);
         consumer.accept(robot);
     }
 
-    private static class CameraPolicyRobotTest extends AppCompatRobotBase {
+    @Test
+    public void testIsCameraCompatTreatmentActive_whenTreatmentForTopActivityIsEnabled() {
+        runTestScenario((robot) -> {
+            robot.applyOnActivity((a)-> {
+                a.createActivityWithComponent();
+                a.enableTreatmentForTopActivity(/* enabled */ true);
+            });
 
-        private final WindowManagerService mWm;
+            robot.checkIsCameraCompatTreatmentActiveForTopActivity(/* active */ true);
+        });
+    }
 
-        CameraPolicyRobotTest(@NonNull WindowManagerService wm,
+    @Test
+    public void testIsCameraCompatTreatmentNotActive_whenTreatmentForTopActivityIsDisabled() {
+        runTestScenario((robot) -> {
+            robot.applyOnActivity((a)-> {
+                a.createActivityWithComponent();
+                a.enableTreatmentForTopActivity(/* enabled */ false);
+            });
+
+            robot.checkIsCameraCompatTreatmentActiveForTopActivity(/* active */ false);
+        });
+    }
+
+    private static class DisplayRotationPolicyRobotTest extends AppCompatRobotBase {
+
+        DisplayRotationPolicyRobotTest(@NonNull WindowManagerService wm,
                 @NonNull ActivityTaskManagerService atm,
                 @NonNull ActivityTaskSupervisor supervisor) {
             super(wm, atm, supervisor);
-            mWm = wm;
-            spyOn(mWm);
         }
 
-        void activateCamera(boolean isCameraActive) {
-            doReturn(isCameraActive).when(activity().top()).isCameraActive();
+        void checkTopActivityHasDisplayRotationCompatPolicy(boolean exists) {
+            Assert.assertEquals(exists, activity().top().mDisplayContent
+                    .mAppCompatCameraPolicy.hasDisplayRotationCompatPolicy());
         }
 
-        void recomputeConfigurationForCameraCompatIfNeeded() {
-            getAppCompatCameraPolicy().recomputeConfigurationForCameraCompatIfNeeded();
+        void checkTopActivityHasCameraCompatFreeformPolicy(boolean exists) {
+            Assert.assertEquals(exists, activity().top().mDisplayContent
+                    .mAppCompatCameraPolicy.hasCameraCompatFreeformPolicy());
         }
 
-        void checkRecomputeConfigurationInvoked(boolean invoked) {
-            if (invoked) {
-                verify(activity().top()).recomputeConfiguration();
-            } else {
-                verify(activity().top(), never()).recomputeConfiguration();
-            }
+        void checkIsCameraCompatTreatmentActiveForTopActivity(boolean active) {
+            Assert.assertEquals(getTopAppCompatCameraPolicy()
+                    .isTreatmentEnabledForActivity(activity().top()), active);
         }
 
-        private AppCompatCameraPolicy getAppCompatCameraPolicy() {
-            return activity().top().mAppCompatController.getAppCompatCameraPolicy();
+        // TODO(b/350460645): Create Desktop Windowing Robot to reuse common functionalities.
+        void allowEnterDesktopMode(boolean isAllowed) {
+            doReturn(isAllowed).when(() ->
+                    DesktopModeLaunchParamsModifier.canEnterDesktopMode(any()));
+        }
+
+        private AppCompatCameraPolicy getTopAppCompatCameraPolicy() {
+            return activity().top().mDisplayContent.mAppCompatCameraPolicy;
         }
     }
-
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
index 1720b64..35c2ee0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationOverridesTest.java
@@ -15,12 +15,8 @@
  */
 package com.android.server.wm;
 
-import static android.content.pm.ActivityInfo.OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH;
 import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
-import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED;
-import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.AppCompatOrientationOverrides.OrientationOverridesState.MIN_COUNT_TO_IGNORE_REQUEST_IN_LOOP;
@@ -31,7 +27,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.compat.testing.PlatformCompatChangeRule;
-import android.content.res.Configuration;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.annotation.NonNull;
@@ -62,82 +57,6 @@
     public TestRule compatChangeRule = new PlatformCompatChangeRule();
 
     @Test
-    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
-    public void testShouldIgnoreRequestedOrientation_activityRelaunching_returnsTrue() {
-        runTestScenario((robot) -> {
-            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
-            robot.activity().createActivityWithComponent();
-            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
-
-            robot.checkShouldIgnoreRequestedOrientation(/* expected */ true,
-                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
-        });
-    }
-
-    @Test
-    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
-    public void testShouldIgnoreRequestedOrientation_cameraCompatTreatment_returnsTrue() {
-        runTestScenario((robot) -> {
-            robot.applyOnConf((c) -> {
-                c.enableCameraCompatTreatment(true);
-                c.enableCameraCompatTreatmentAtBuildTime(true);
-                c.enablePolicyForIgnoringRequestedOrientation(true);
-            });
-            robot.applyOnActivity((a) -> {
-                a.createActivityWithComponentInNewTask();
-                a.enableTreatmentForTopActivity(true);
-            });
-            robot.prepareRelaunchingAfterRequestedOrientationChanged(false);
-
-            robot.checkShouldIgnoreRequestedOrientation(/* expected */ true,
-                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
-        });
-    }
-
-    @Test
-    public void testShouldIgnoreRequestedOrientation_overrideDisabled_returnsFalse() {
-        runTestScenario((robot) -> {
-            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
-
-            robot.activity().createActivityWithComponent();
-            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
-
-            robot.checkShouldIgnoreRequestedOrientation(/* expected */ false,
-                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
-        });
-    }
-
-    @Test
-    public void testShouldIgnoreRequestedOrientation_propertyIsTrue_returnsTrue() {
-        runTestScenario((robot) -> {
-            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
-            robot.prop().enable(PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION);
-
-            robot.activity().createActivityWithComponent();
-            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
-
-            robot.checkShouldIgnoreRequestedOrientation(/* expected */ true,
-                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
-        });
-    }
-
-    @Test
-    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
-    public void testShouldIgnoreRequestedOrientation_propertyIsFalseAndOverride_returnsFalse()
-            throws Exception {
-        runTestScenario((robot) -> {
-            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
-            robot.prop().disable(PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION);
-
-            robot.activity().createActivityWithComponent();
-            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
-
-            robot.checkShouldIgnoreRequestedOrientation(/* expected */ false,
-                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
-        });
-    }
-
-    @Test
     public void testShouldIgnoreOrientationRequestLoop_overrideDisabled_returnsFalse() {
         runTestScenario((robot) -> {
             robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
@@ -239,21 +158,6 @@
         });
     }
 
-    @Test
-    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
-    public void testShouldIgnoreRequestedOrientation_flagIsDisabled_returnsFalse() {
-        runTestScenario((robot) -> {
-            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
-            robot.applyOnActivity((a) -> {
-                a.createActivityWithComponent();
-                a.setLetterboxedForFixedOrientationAndAspectRatio(false);
-            });
-
-            robot.checkShouldIgnoreRequestedOrientation(/* expected */ false,
-                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
-        });
-    }
-
     /**
      * Runs a test scenario providing a Robot.
      */
@@ -276,10 +180,6 @@
             mTestCurrentTimeMillisSupplier = new CurrentTimeMillisSupplierFake();
         }
 
-        void prepareRelaunchingAfterRequestedOrientationChanged(boolean enabled) {
-            getTopOrientationOverrides().setRelaunchingAfterRequestedOrientationChanged(enabled);
-        }
-
         // Useful to reduce timeout during tests
         void prepareMockedTime() {
             getTopOrientationOverrides().mOrientationOverridesState.mCurrentTimeMillisSupplier =
@@ -290,12 +190,6 @@
             mTestCurrentTimeMillisSupplier.delay(SET_ORIENTATION_REQUEST_COUNTER_TIMEOUT_MS);
         }
 
-        void checkShouldIgnoreRequestedOrientation(boolean expected,
-                @Configuration.Orientation int requestedOrientation) {
-            assertEquals(expected, getTopOrientationOverrides()
-                    .shouldIgnoreRequestedOrientation(requestedOrientation));
-        }
-
         void checkExpectedLoopCount(int expectedCount) {
             assertEquals(expectedCount, getTopOrientationOverrides()
                     .getSetOrientationRequestCounter());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
index 9885a2d..aa520e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatOrientationPolicyTest.java
@@ -18,6 +18,8 @@
 
 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_REFRESH;
+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;
@@ -33,13 +35,16 @@
 import static android.content.pm.PackageManager.USER_MIN_ASPECT_RATIO_FULLSCREEN;
 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE;
 import static android.view.WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE;
+import static android.view.WindowManager.PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.verify;
 
 import android.compat.testing.PlatformCompatChangeRule;
 import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.annotation.NonNull;
@@ -266,7 +271,7 @@
                 c.enableCameraCompatTreatmentAtBuildTime(true);
             });
             robot.applyOnActivity((a) -> {
-                a.createActivityWithComponentInNewTask();
+                a.createActivityWithComponentInNewTaskAndDisplay();
                 a.setTopActivityEligibleForOrientationOverride(false);
             });
 
@@ -285,7 +290,7 @@
                 c.enableCameraCompatTreatmentAtBuildTime(true);
             });
             robot.applyOnActivity((a) -> {
-                a.createActivityWithComponentInNewTask();
+                a.createActivityWithComponentInNewTaskAndDisplay();
                 a.setTopActivityEligibleForOrientationOverride(true);
             });
 
@@ -315,7 +320,7 @@
                 c.enableCameraCompatTreatmentAtBuildTime(true);
             });
             robot.applyOnActivity((a) -> {
-                a.createActivityWithComponentInNewTask();
+                a.createActivityWithComponentInNewTaskAndDisplay();
                 a.setTopActivityCameraActive(false);
             });
 
@@ -398,6 +403,97 @@
         });
     }
 
+    @Test
+    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
+    public void testShouldIgnoreRequestedOrientation_activityRelaunching_returnsTrue() {
+        runTestScenario((robot) -> {
+            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
+            robot.activity().createActivityWithComponent();
+            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
+
+            robot.checkShouldIgnoreRequestedOrientation(/* expected */ true,
+                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
+        });
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
+    public void testShouldIgnoreRequestedOrientation_cameraCompatTreatment_returnsTrue() {
+        runTestScenario((robot) -> {
+            robot.applyOnConf((c) -> {
+                c.enableCameraCompatTreatment(true);
+                c.enableCameraCompatTreatmentAtBuildTime(true);
+                c.enablePolicyForIgnoringRequestedOrientation(true);
+            });
+            robot.applyOnActivity((a) -> {
+                a.createActivityWithComponentInNewTask();
+                a.enableTreatmentForTopActivity(true);
+            });
+            robot.prepareRelaunchingAfterRequestedOrientationChanged(false);
+
+            robot.checkShouldIgnoreRequestedOrientation(/* expected */ true,
+                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
+        });
+    }
+
+    @Test
+    public void testShouldIgnoreRequestedOrientation_overrideDisabled_returnsFalse() {
+        runTestScenario((robot) -> {
+            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
+
+            robot.activity().createActivityWithComponent();
+            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
+
+            robot.checkShouldIgnoreRequestedOrientation(/* expected */ false,
+                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
+        });
+    }
+
+    @Test
+    public void testShouldIgnoreRequestedOrientation_propertyIsTrue_returnsTrue() {
+        runTestScenario((robot) -> {
+            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
+            robot.prop().enable(PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION);
+
+            robot.activity().createActivityWithComponent();
+            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
+
+            robot.checkShouldIgnoreRequestedOrientation(/* expected */ true,
+                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
+        });
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION})
+    public void testShouldIgnoreRequestedOrientation_propertyIsFalseAndOverride_returnsFalse()
+            throws Exception {
+        runTestScenario((robot) -> {
+            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
+            robot.prop().disable(PROPERTY_COMPAT_IGNORE_REQUESTED_ORIENTATION);
+
+            robot.activity().createActivityWithComponent();
+            robot.prepareRelaunchingAfterRequestedOrientationChanged(true);
+
+            robot.checkShouldIgnoreRequestedOrientation(/* expected */ false,
+                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
+        });
+    }
+
+    @Test
+    @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_DISABLE_REFRESH})
+    public void testShouldIgnoreRequestedOrientation_flagIsDisabled_returnsFalse() {
+        runTestScenario((robot) -> {
+            robot.conf().enablePolicyForIgnoringRequestedOrientation(true);
+            robot.applyOnActivity((a) -> {
+                a.createActivityWithComponent();
+                a.setLetterboxedForFixedOrientationAndAspectRatio(false);
+            });
+
+            robot.checkShouldIgnoreRequestedOrientation(/* expected */ false,
+                    /* requestedOrientation */ SCREEN_ORIENTATION_UNSPECIFIED);
+        });
+    }
+
 
     /**
      * Runs a test scenario with an existing activity providing a Robot.
@@ -440,6 +536,10 @@
             }
         }
 
+        void prepareRelaunchingAfterRequestedOrientationChanged(boolean enabled) {
+            getTopOrientationOverrides().setRelaunchingAfterRequestedOrientationChanged(enabled);
+        }
+
         int overrideOrientationIfNeeded(@ActivityInfo.ScreenOrientation int candidate) {
             return activity().top().mAppCompatController.getOrientationPolicy()
                     .overrideOrientationIfNeeded(candidate);
@@ -451,12 +551,27 @@
 
         void checkOverrideOrientation(@ActivityInfo.ScreenOrientation int candidate,
                                       @ActivityInfo.ScreenOrientation int expected) {
-            Assert.assertEquals(expected, overrideOrientationIfNeeded(candidate));
+            assertEquals(expected, overrideOrientationIfNeeded(candidate));
         }
 
         void checkOverrideOrientationIsNot(@ActivityInfo.ScreenOrientation int candidate,
                                            @ActivityInfo.ScreenOrientation int notExpected) {
             Assert.assertNotEquals(notExpected, overrideOrientationIfNeeded(candidate));
         }
+
+        void checkShouldIgnoreRequestedOrientation(boolean expected,
+                @Configuration.Orientation int requestedOrientation) {
+            assertEquals(expected, getTopAppCompatOrientationPolicy()
+                    .shouldIgnoreRequestedOrientation(requestedOrientation));
+        }
+
+        private AppCompatOrientationOverrides getTopOrientationOverrides() {
+            return activity().top().mAppCompatController.getAppCompatOverrides()
+                    .getAppCompatOrientationOverrides();
+        }
+
+        private AppCompatOrientationPolicy getTopAppCompatOrientationPolicy() {
+            return activity().top().mAppCompatController.getOrientationPolicy();
+        }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 6957502..5739a04 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -117,8 +117,8 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.util.ArraySet;
 import android.view.Display;
@@ -2832,7 +2832,7 @@
         doReturn(true).when(() ->
                 DesktopModeLaunchParamsModifier.canEnterDesktopMode(any()));
 
-        assertNotNull(createNewDisplay().mCameraCompatFreeformPolicy);
+        assertTrue(createNewDisplay().mAppCompatCameraPolicy.hasCameraCompatFreeformPolicy());
     }
 
     @DisableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
@@ -2841,14 +2841,14 @@
         doReturn(true).when(() ->
                 DesktopModeLaunchParamsModifier.canEnterDesktopMode(any()));
 
-        assertNull(createNewDisplay().mCameraCompatFreeformPolicy);
+        assertFalse(createNewDisplay().mAppCompatCameraPolicy.hasCameraCompatFreeformPolicy());
     }
 
     @EnableFlags(FLAG_CAMERA_COMPAT_FOR_FREEFORM)
     @DisableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     @Test
     public void desktopWindowingFlagNotEnabled_cameraCompatFreeformPolicyIsNull() {
-        assertNull(createNewDisplay().mCameraCompatFreeformPolicy);
+        assertFalse(createNewDisplay().mAppCompatCameraPolicy.hasCameraCompatFreeformPolicy());
     }
 
     private void removeRootTaskTests(Runnable runnable) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index e3a8542..2e488d8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -1607,6 +1607,7 @@
                     .thenReturn(mMockDeviceStateManager);
 
             mDeviceStateController = mock(DeviceStateController.class);
+            mMockDisplayContent.mAppCompatCameraPolicy = mock(AppCompatCameraPolicy.class);
             mTarget = new TestDisplayRotation(mMockDisplayContent, mMockDisplayAddress,
                     mMockDisplayPolicy, mMockDisplayWindowSettings, mMockContext,
                     mDeviceStateController);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
index 74e2d44..51b3c48 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java
@@ -636,8 +636,9 @@
     @Test
     @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
     public void shouldOverrideMinAspectRatioForCamera_overrideEnabled_returnsTrue() {
-        doReturn(true).when(mActivity).isCameraActive();
-        mController = new LetterboxUiController(mWm, mActivity);
+        mActivity = setUpActivityWithComponent();
+        doReturn(true).when(mActivity.mAppCompatController
+                .getAppCompatCameraOverrides()).isCameraActive();
 
         assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
                 .shouldOverrideMinAspectRatioForCamera());
@@ -647,9 +648,10 @@
     @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
     public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideEnabled_returnsTrue()
             throws Exception {
-        doReturn(true).when(mActivity).isCameraActive();
         mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
-        mController = new LetterboxUiController(mWm, mActivity);
+        mActivity = setUpActivityWithComponent();
+        doReturn(true).when(mActivity.mAppCompatController
+                .getAppCompatCameraOverrides()).isCameraActive();
 
         assertTrue(mActivity.mAppCompatController.getAppCompatCameraOverrides()
                 .shouldOverrideMinAspectRatioForCamera());
@@ -659,9 +661,10 @@
     @EnableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
     public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideEnabled_returnsFalse()
             throws Exception {
-        doReturn(false).when(mActivity).isCameraActive();
         mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
-        mController = new LetterboxUiController(mWm, mActivity);
+        mActivity = setUpActivityWithComponent();
+        doReturn(false).when(mActivity.mAppCompatController
+                .getAppCompatCameraOverrides()).isCameraActive();
 
         assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
                 .shouldOverrideMinAspectRatioForCamera());
@@ -671,9 +674,10 @@
     @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
     public void shouldOverrideMinAspectRatioForCamera_propertyTrue_overrideDisabled_returnsFalse()
             throws Exception {
-        doReturn(true).when(mActivity).isCameraActive();
         mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ true);
-        mController = new LetterboxUiController(mWm, mActivity);
+        mActivity = setUpActivityWithComponent();
+        doReturn(true).when(mActivity.mAppCompatController
+                .getAppCompatCameraOverrides()).isCameraActive();
 
         assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
                 .shouldOverrideMinAspectRatioForCamera());
@@ -682,8 +686,9 @@
     @Test
     @DisableCompatChanges({OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA})
     public void shouldOverrideMinAspectRatioForCamera_overrideDisabled_returnsFalse() {
-        doReturn(true).when(mActivity).isCameraActive();
-        mController = new LetterboxUiController(mWm, mActivity);
+        mActivity = setUpActivityWithComponent();
+        doReturn(true).when(mActivity.mAppCompatController
+                .getAppCompatCameraOverrides()).isCameraActive();
 
         assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
                 .shouldOverrideMinAspectRatioForCamera());
@@ -694,7 +699,7 @@
     public void shouldOverrideMinAspectRatioForCamera_propertyFalse_overrideEnabled_returnsFalse()
             throws Exception {
         mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
-        mController = new LetterboxUiController(mWm, mActivity);
+        mActivity = setUpActivityWithComponent();
 
         assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
                 .shouldOverrideMinAspectRatioForCamera());
@@ -705,8 +710,11 @@
     public void shouldOverrideMinAspectRatioForCamera_propertyFalse_noOverride_returnsFalse()
             throws Exception {
         mockThatProperty(PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE, /* value */ false);
-        doReturn(true).when(mActivity).isCameraActive();
-        mController = new LetterboxUiController(mWm, mActivity);
+
+        mActivity = setUpActivityWithComponent();
+
+        doReturn(true).when(mActivity.mAppCompatController
+                .getAppCompatCameraOverrides()).isCameraActive();
 
         assertFalse(mActivity.mAppCompatController.getAppCompatCameraOverrides()
                 .shouldOverrideMinAspectRatioForCamera());
@@ -848,8 +856,8 @@
         assertEquals(1.5f, mController.getFixedOrientationLetterboxAspectRatio(
                 mActivity.getParent().getConfiguration()), /* delta */ 0.01);
 
-        spyOn(mDisplayContent.mDisplayRotationCompatPolicy);
-        doReturn(true).when(mDisplayContent.mDisplayRotationCompatPolicy)
+        spyOn(mDisplayContent.mAppCompatCameraPolicy);
+        doReturn(true).when(mDisplayContent.mAppCompatCameraPolicy)
                 .isTreatmentEnabledForActivity(eq(mActivity));
 
         assertEquals(mController.getSplitScreenAspectRatio(),
@@ -980,6 +988,7 @@
                 .setComponent(ComponentName.createRelative(mContext,
                         com.android.server.wm.LetterboxUiControllerTest.class.getName()))
                 .build();
+        spyOn(activity.mAppCompatController.getAppCompatCameraOverrides());
         return activity;
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index c962a3f..4220f31 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -442,15 +442,7 @@
                 dc.getDisplayPolicy().release();
                 // Unregister SensorEventListener (foldable device may register for hinge angle).
                 dc.getDisplayRotation().onDisplayRemoved();
-                if (dc.mDisplayRotationCompatPolicy != null) {
-                    dc.mDisplayRotationCompatPolicy.dispose();
-                }
-                if (dc.mCameraCompatFreeformPolicy != null) {
-                    dc.mCameraCompatFreeformPolicy.dispose();
-                }
-                if (dc.mCameraStateMonitor != null) {
-                    dc.mCameraStateMonitor.dispose();
-                }
+                dc.mAppCompatCameraPolicy.dispose();
             }
         }