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

Commit 00f12d74 authored by Mariia Sandrikova's avatar Mariia Sandrikova Committed by Android (Google) Code Review
Browse files

Merge changes from topic "camera-orientation-override" into tm-qpr-dev

* changes:
  [6/n] Camera Compat: Orientation override for camera only
  [5/n] Camera Compat: Toasts explaining compat treatment
parents 01ce329a ccc0c90b
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -1237,6 +1237,18 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
    @Overridable
    public static final long OVERRIDE_ANY_ORIENTATION = 265464455L;

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

    /**
     * This override fixes display orientation to landscape natural orientation when a task is
     * fullscreen. While display rotation is fixed to landscape, the orientation requested by the
+2 −0
Original line number Diff line number Diff line
@@ -2562,6 +2562,8 @@
  <java-symbol type="string" name="zen_mode_default_weekends_name" />
  <java-symbol type="string" name="zen_mode_default_events_name" />
  <java-symbol type="string" name="zen_mode_default_every_night_name" />
  <java-symbol type="string" name="display_rotation_camera_compat_toast_after_rotation" />
  <java-symbol type="string" name="display_rotation_camera_compat_toast_in_split_screen" />
  <java-symbol type="array" name="config_system_condition_providers" />
  <java-symbol type="string" name="muted_by" />
  <java-symbol type="string" name="zen_mode_alarm" />
+77 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.wm;

import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
@@ -34,6 +36,7 @@ import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.RefreshCallbackItem;
import android.app.servertransaction.ResumeActivityItem;
@@ -44,10 +47,13 @@ import android.os.Handler;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.widget.Toast;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.server.UiThread;

import java.util.Map;
import java.util.Set;
@@ -232,6 +238,27 @@ final class DisplayRotationCompatPolicy {
        activity.mLetterboxUiController.setIsRefreshAfterRotationRequested(false);
    }

    /**
     * Notifies that animation in {@link ScreenAnimationRotation} 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 (!isTreatmentEnabledForDisplay() || mCameraIdPackageBiMap.isEmpty()) {
            return;
        }
        ActivityRecord topActivity = mDisplayContent.topRunningActivity(
                    /* considerKeyguardState= */ true);
        if (topActivity == null
                // Checking windowing mode on activity level because we don't want to
                // show toast in case of activity embedding.
                || topActivity.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
            return;
        }
        showToast(R.string.display_rotation_camera_compat_toast_after_rotation);
    }

    String getSummaryForDisplayRotationHistoryRecord() {
        String summaryIfEnabled = "";
        if (isTreatmentEnabledForDisplay()) {
@@ -281,6 +308,10 @@ final class DisplayRotationCompatPolicy {
                && mDisplayContent.getDisplay().getType() == TYPE_INTERNAL;
    }

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

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

    private boolean isCameraActiveInFullscreen(@NonNull ActivityRecord activity) {
        return !activity.inMultiWindowMode()
                && mCameraIdPackageBiMap.containsPackageName(activity.packageName)
                && activity.mLetterboxUiController.shouldForceRotateForCameraCompat();
    }
@@ -334,7 +369,31 @@ final class DisplayRotationCompatPolicy {
            }
            mCameraIdPackageBiMap.put(packageName, cameraId);
        }
        ActivityRecord topActivity = mDisplayContent.topRunningActivity(
                    /* considerKeyguardState= */ true);
        if (topActivity == null || topActivity.getTask() == null) {
            return;
        }
        // Checking whether an activity in fullscreen rather than the task as this camera compat
        // treatment doesn't cover activity embedding.
        if (topActivity.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
            if (topActivity.mLetterboxUiController.isOverrideOrientationOnlyForCameraEnabled()) {
                topActivity.recomputeConfiguration();
            }
            updateOrientationWithWmLock();
            return;
        }
        // Checking that the whole app is in multi-window mode as we shouldn't show toast
        // for the activity embedding case.
        if (topActivity.getTask().getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW) {
            showToast(R.string.display_rotation_camera_compat_toast_in_split_screen);
        }
    }

    @VisibleForTesting
    void showToast(@StringRes int stringRes) {
        UiThread.getHandler().post(
                () -> Toast.makeText(mWmService.mContext, stringRes, Toast.LENGTH_LONG).show());
    }

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

@@ -396,6 +466,10 @@ final class DisplayRotationCompatPolicy {
        private final Map<String, String> mPackageToCameraIdMap = new ArrayMap<>();
        private final Map<String, String> mCameraIdToPackageMap = new ArrayMap<>();

        boolean isEmpty() {
            return mCameraIdToPackageMap.isEmpty();
        }

        void put(String packageName, String cameraId) {
            // Always using the last connected camera ID for the package even for the concurrent
            // camera use case since we can't guess which camera is more important anyway.
+6 −9
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.wm;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ALLOW_IGNORE_ORIENTATION_REQUEST;
import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_CAMERA_COMPAT_TREATMENT;
import static com.android.server.wm.LetterboxConfigurationDeviceConfig.KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY;

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

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

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

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

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

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

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

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

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

    // Whether enabling rotation compat policy for immersive apps that prevents auto rotation
    // into non-optimal screen orientation while in fullscreen. This is needed because immersive
    // apps, such as games, are often not optimized for all orientations and can have a poor UX
@@ -101,6 +111,8 @@ final class LetterboxConfigurationDeviceConfig
     */
    boolean getFlag(String key) {
        switch (key) {
            case KEY_ENABLE_CAMERA_COMPAT_TREATMENT:
                return mIsCameraCompatTreatmentEnabled;
            case KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY:
                return mIsDisplayRotationImmersiveAppCompatPolicyEnabled;
            case KEY_ALLOW_IGNORE_ORIENTATION_REQUEST:
@@ -116,6 +128,10 @@ final class LetterboxConfigurationDeviceConfig
            throw new AssertionError("Haven't found default value for flag: " + key);
        }
        switch (key) {
            case KEY_ENABLE_CAMERA_COMPAT_TREATMENT:
                mIsCameraCompatTreatmentEnabled =
                        getDeviceConfig(key, defaultValue);
                break;
            case KEY_ENABLE_DISPLAY_ROTATION_IMMERSIVE_APP_COMPAT_POLICY:
                mIsDisplayRotationImmersiveAppCompatPolicyEnabled =
                        getDeviceConfig(key, defaultValue);
Loading