Loading services/core/java/com/android/server/wm/ActivityRecord.java +4 −17 Original line number Diff line number Diff line Loading @@ -6535,9 +6535,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // 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) { Loading Loading @@ -8194,7 +8192,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) { if (mAppCompatController.getAppCompatOrientationOverrides() if (mAppCompatController.getOrientationPolicy() .shouldIgnoreRequestedOrientation(requestedOrientation)) { return; } Loading Loading @@ -10030,16 +10028,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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"); Loading Loading @@ -10187,11 +10175,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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); } Loading services/core/java/com/android/server/wm/AppCompatCameraOverrides.java +10 −2 Original line number Diff line number Diff line Loading @@ -97,8 +97,7 @@ class AppCompatCameraOverrides { * </ul> */ boolean shouldOverrideMinAspectRatioForCamera() { return mActivityRecord.isCameraActive() && mAllowMinAspectRatioOverrideOptProp return isCameraActive() && mAllowMinAspectRatioOverrideOptProp .shouldEnableWithOptInOverrideAndOptOutProperty( isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA)); } Loading Loading @@ -173,6 +172,15 @@ class AppCompatCameraOverrides { OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT); } /** * @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. */ Loading services/core/java/com/android/server/wm/AppCompatCameraPolicy.java +140 −16 Original line number Diff line number Diff line Loading @@ -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; 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; } } @NonNull private final AppCompatCameraOverrides mAppCompatCameraOverrides; void onActivityRefreshed(@NonNull ActivityRecord activity) { if (mActivityRefresher != null) { mActivityRefresher.onActivityRefreshed(activity); } } AppCompatCameraPolicy(@NonNull ActivityRecord activityRecord, @NonNull AppCompatCameraOverrides appCompatCameraOverrides) { mActivityRecord = activityRecord; mAppCompatCameraOverrides = appCompatCameraOverrides; /** * "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); } } void recomputeConfigurationForCameraCompatIfNeeded() { if (mAppCompatCameraOverrides.shouldRecomputeConfigurationForCameraCompat()) { mActivityRecord.recomputeConfiguration(); /** * 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; } } services/core/java/com/android/server/wm/AppCompatController.java +12 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -25,17 +26,18 @@ import com.android.server.wm.utils.OptPropFactory; */ 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); Loading @@ -49,8 +51,6 @@ class AppCompatController { mAppCompatOverrides, tmpController::shouldApplyUserFullscreenOverride, tmpController::shouldApplyUserMinAspectRatioOverride, tmpController::isSystemOverrideToFullscreenEnabled); mAppCompatCameraPolicy = new AppCompatCameraPolicy(activityRecord, mAppCompatOverrides.getAppCompatCameraOverrides()); } @NonNull Loading @@ -63,11 +63,6 @@ class AppCompatController { return mOrientationPolicy; } @NonNull AppCompatCameraPolicy getAppCompatCameraPolicy() { return mAppCompatCameraPolicy; } @NonNull AppCompatOverrides getAppCompatOverrides() { return mAppCompatOverrides; Loading @@ -82,4 +77,12 @@ class AppCompatController { AppCompatCameraOverrides getAppCompatCameraOverrides() { return mAppCompatOverrides.getAppCompatCameraOverrides(); } @Nullable AppCompatCameraPolicy getAppCompatCameraPolicy() { if (mActivityRecord.mDisplayContent != null) { return mActivityRecord.mDisplayContent.mAppCompatCameraPolicy; } return null; } } services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java +8 −71 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQU 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; Loading @@ -31,8 +30,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS 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; Loading @@ -51,6 +48,8 @@ class AppCompatOrientationOverrides { @NonNull private final ActivityRecord mActivityRecord; @NonNull private final AppCompatCameraOverrides mAppCompatCameraOverrides; @NonNull private final OptPropFactory.OptProp mIgnoreRequestedOrientationOptProp; Loading @@ -62,8 +61,10 @@ class AppCompatOrientationOverrides { 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( Loading @@ -76,59 +77,9 @@ class AppCompatOrientationOverrides { 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)); } /** Loading Loading @@ -183,20 +134,6 @@ class AppCompatOrientationOverrides { 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; Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +4 −17 Original line number Diff line number Diff line Loading @@ -6535,9 +6535,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // 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) { Loading Loading @@ -8194,7 +8192,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } void setRequestedOrientation(@ActivityInfo.ScreenOrientation int requestedOrientation) { if (mAppCompatController.getAppCompatOrientationOverrides() if (mAppCompatController.getOrientationPolicy() .shouldIgnoreRequestedOrientation(requestedOrientation)) { return; } Loading Loading @@ -10030,16 +10028,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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"); Loading Loading @@ -10187,11 +10175,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A 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); } Loading
services/core/java/com/android/server/wm/AppCompatCameraOverrides.java +10 −2 Original line number Diff line number Diff line Loading @@ -97,8 +97,7 @@ class AppCompatCameraOverrides { * </ul> */ boolean shouldOverrideMinAspectRatioForCamera() { return mActivityRecord.isCameraActive() && mAllowMinAspectRatioOverrideOptProp return isCameraActive() && mAllowMinAspectRatioOverrideOptProp .shouldEnableWithOptInOverrideAndOptOutProperty( isCompatChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_ONLY_FOR_CAMERA)); } Loading Loading @@ -173,6 +172,15 @@ class AppCompatCameraOverrides { OVERRIDE_CAMERA_COMPAT_DISABLE_FREEFORM_WINDOWING_TREATMENT); } /** * @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. */ Loading
services/core/java/com/android/server/wm/AppCompatCameraPolicy.java +140 −16 Original line number Diff line number Diff line Loading @@ -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; 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; } } @NonNull private final AppCompatCameraOverrides mAppCompatCameraOverrides; void onActivityRefreshed(@NonNull ActivityRecord activity) { if (mActivityRefresher != null) { mActivityRefresher.onActivityRefreshed(activity); } } AppCompatCameraPolicy(@NonNull ActivityRecord activityRecord, @NonNull AppCompatCameraOverrides appCompatCameraOverrides) { mActivityRecord = activityRecord; mAppCompatCameraOverrides = appCompatCameraOverrides; /** * "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); } } void recomputeConfigurationForCameraCompatIfNeeded() { if (mAppCompatCameraOverrides.shouldRecomputeConfigurationForCameraCompat()) { mActivityRecord.recomputeConfiguration(); /** * 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; } }
services/core/java/com/android/server/wm/AppCompatController.java +12 −9 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -25,17 +26,18 @@ import com.android.server.wm.utils.OptPropFactory; */ 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); Loading @@ -49,8 +51,6 @@ class AppCompatController { mAppCompatOverrides, tmpController::shouldApplyUserFullscreenOverride, tmpController::shouldApplyUserMinAspectRatioOverride, tmpController::isSystemOverrideToFullscreenEnabled); mAppCompatCameraPolicy = new AppCompatCameraPolicy(activityRecord, mAppCompatOverrides.getAppCompatCameraOverrides()); } @NonNull Loading @@ -63,11 +63,6 @@ class AppCompatController { return mOrientationPolicy; } @NonNull AppCompatCameraPolicy getAppCompatCameraPolicy() { return mAppCompatCameraPolicy; } @NonNull AppCompatOverrides getAppCompatOverrides() { return mAppCompatOverrides; Loading @@ -82,4 +77,12 @@ class AppCompatController { AppCompatCameraOverrides getAppCompatCameraOverrides() { return mAppCompatOverrides.getAppCompatCameraOverrides(); } @Nullable AppCompatCameraPolicy getAppCompatCameraPolicy() { if (mActivityRecord.mDisplayContent != null) { return mActivityRecord.mDisplayContent.mAppCompatCameraPolicy; } return null; } }
services/core/java/com/android/server/wm/AppCompatOrientationOverrides.java +8 −71 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import static android.content.pm.ActivityInfo.OVERRIDE_ENABLE_COMPAT_IGNORE_REQU 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; Loading @@ -31,8 +30,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS 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; Loading @@ -51,6 +48,8 @@ class AppCompatOrientationOverrides { @NonNull private final ActivityRecord mActivityRecord; @NonNull private final AppCompatCameraOverrides mAppCompatCameraOverrides; @NonNull private final OptPropFactory.OptProp mIgnoreRequestedOrientationOptProp; Loading @@ -62,8 +61,10 @@ class AppCompatOrientationOverrides { 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( Loading @@ -76,59 +77,9 @@ class AppCompatOrientationOverrides { 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)); } /** Loading Loading @@ -183,20 +134,6 @@ class AppCompatOrientationOverrides { 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; Loading