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

Commit ff362225 authored by Garfield Tan's avatar Garfield Tan
Browse files

Add a flag to fix rotation to user rotation only.

It also does a few more things:
1. Add a command to manually test the flag.
2. Refactor DisplayRotation a bit to make it unit testable.
3. Add some core unit tests for DisplayRotation.

Bug: 113252523
Test: Manual test.
atest WmTests:DisplayRotationTests

Change-Id: I00c4a44e4d2f637590e8b13f7e6194624c04c58f
parent 18b665d4
Loading
Loading
Loading
Loading
+67 −21
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;

import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -30,6 +31,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.power.V1_0.PowerHint;
import android.net.Uri;
import android.os.Handler;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -57,6 +59,7 @@ public class DisplayRotation {
    private final WindowManagerService mService;
    private final DisplayContent mDisplayContent;
    private final DisplayPolicy mDisplayPolicy;
    private final DisplayWindowSettings mDisplayWindowSettings;
    private final Context mContext;
    private final Object mLock;

@@ -71,10 +74,6 @@ public class DisplayRotation {
    private StatusBarManagerInternal mStatusBarManagerInternal;
    private SettingsObserver mSettingsObserver;

    // Default display does not rotate, apps that require non-default orientation will have to
    // have the orientation emulated.
    private boolean mForceDefaultOrientation;

    private int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

    @VisibleForTesting
@@ -93,6 +92,13 @@ public class DisplayRotation {
    private int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
    private int mUserRotation = Surface.ROTATION_0;

    /**
     * A flag to indicate if the display rotation should be fixed to user specified rotation
     * regardless of all other states (including app requrested orientation). {@code true} the
     * display rotation should be fixed to user specified rotation, {@code false} otherwise.
     */
    private boolean mFixedToUserRotation;

    private int mDemoHdmiRotation;
    private int mDemoRotation;
    private boolean mDemoHdmiRotationLock;
@@ -100,15 +106,17 @@ public class DisplayRotation {

    DisplayRotation(WindowManagerService service, DisplayContent displayContent) {
        this(service, displayContent, displayContent.getDisplayPolicy(),
                service.mContext, service.getWindowManagerLock());
                service.mDisplayWindowSettings, service.mContext, service.getWindowManagerLock());
    }

    @VisibleForTesting
    DisplayRotation(WindowManagerService service, DisplayContent displayContent,
            DisplayPolicy displayPolicy, Context context, Object lock) {
            DisplayPolicy displayPolicy, DisplayWindowSettings displayWindowSettings,
            Context context, Object lock) {
        mService = service;
        mDisplayContent = displayContent;
        mDisplayPolicy = displayPolicy;
        mDisplayWindowSettings = displayWindowSettings;
        mContext = context;
        mLock = lock;
        isDefaultDisplay = displayContent.isDefaultDisplay;
@@ -204,12 +212,19 @@ public class DisplayRotation {
        // so if the orientation is forced, we need to respect that no matter what.
        final boolean isTv = mContext.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_LEANBACK);
        mForceDefaultOrientation = ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv) &&
                res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation) &&
        final boolean forceDefaultOrientationInRes =
                res.getBoolean(com.android.internal.R.bool.config_forceDefaultOrientation);
        final boolean forceDefaultOrienation =
                ((longSizeDp >= 960 && shortSizeDp >= 720) || isCar || isTv)
                        && forceDefaultOrientationInRes
                        // For debug purposes the next line turns this feature off with:
                        // $ adb shell setprop config.override_forced_orient true
                        // $ adb shell wm size reset
                !"true".equals(SystemProperties.get("config.override_forced_orient"));
                        && !"true".equals(SystemProperties.get("config.override_forced_orient"));
        // Configuration says we force to use the default orientation. We can fall back to fix
        // rotation to only user rotation. As long as OEM doesn't change user rotation then the
        // rotation of this display is effectively stuck at 0 deg.
        setFixedToUserRotation(forceDefaultOrienation);
    }

    void setRotation(int rotation) {
@@ -227,7 +242,14 @@ public class DisplayRotation {
        }
    }

    void restoreUserRotation(int userRotationMode, int userRotation) {
    void restoreSettings(int userRotationMode, int userRotation,
            boolean fixedToUserRotation) {
        mFixedToUserRotation = fixedToUserRotation;

        // We will retrieve user rotation and user rotation mode from settings for default display.
        if (isDefaultDisplay) {
            return;
        }
        if (userRotationMode != WindowManagerPolicy.USER_ROTATION_FREE
                && userRotationMode != WindowManagerPolicy.USER_ROTATION_LOCKED) {
            Slog.w(TAG, "Trying to restore an invalid user rotation mode " + userRotationMode
@@ -243,6 +265,18 @@ public class DisplayRotation {
        mUserRotation = userRotation;
    }

    void setFixedToUserRotation(boolean fixedToUserRotation) {
        if (mFixedToUserRotation == fixedToUserRotation) {
            return;
        }

        mFixedToUserRotation = fixedToUserRotation;
        mDisplayWindowSettings.setFixedToUserRotation(mDisplayContent,
                fixedToUserRotation);
        mService.updateRotation(true /* alwaysSendConfiguration */,
                false /* forceRelayout */);
    }

    private void setUserRotation(int userRotationMode, int userRotation) {
        if (isDefaultDisplay) {
            // We'll be notified via settings listener, so we don't need to update internal values.
@@ -265,7 +299,7 @@ public class DisplayRotation {
            mUserRotation = userRotation;
            changed = true;
        }
        mService.mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
        mDisplayWindowSettings.setUserRotation(mDisplayContent, userRotationMode,
                userRotation);
        if (changed) {
            mService.updateRotation(true /* alwaysSendConfiguration */,
@@ -291,9 +325,8 @@ public class DisplayRotation {
                Settings.System.ACCELEROMETER_ROTATION, 0, UserHandle.USER_CURRENT) == 0;
    }

    /** @return true if com.android.internal.R.bool#config_forceDefaultOrientation is true. */
    boolean isDefaultOrientationForced() {
        return mForceDefaultOrientation;
    boolean isFixedToUserRotation() {
        return mFixedToUserRotation;
    }

    public int getLandscapeRotation() {
@@ -399,6 +432,12 @@ public class DisplayRotation {
     * screen is switched off.
     */
    private boolean needSensorRunning() {
        if (mFixedToUserRotation) {
            // We are sure we only respect user rotation settings, so we are sure we will not
            // support sensor rotation.
            return false;
        }

        if (mSupportAutoRotation) {
            if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR
                    || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
@@ -459,8 +498,8 @@ public class DisplayRotation {
                        );
        }

        if (mForceDefaultOrientation) {
            return Surface.ROTATION_0;
        if (mFixedToUserRotation) {
            return mUserRotation;
        }

        int sensorRotation = mOrientationListener != null
@@ -701,8 +740,8 @@ public class DisplayRotation {
        // demo, hdmi, vr, etc mode.

        // Determine if the rotation is currently forced.
        if (mForceDefaultOrientation) {
            return false; // Rotation is forced to default orientation.
        if (mFixedToUserRotation) {
            return false; // Rotation is forced to user settings.
        }

        final int lidState = mDisplayPolicy.getLidState();
@@ -861,6 +900,7 @@ public class DisplayRotation {
        pw.print(" mDemoHdmiRotationLock=" + mDemoHdmiRotationLock);
        pw.println(" mUndockedHdmiRotation=" + Surface.rotationToString(mUndockedHdmiRotation));
        pw.println(prefix + "  mLidOpenRotation=" + Surface.rotationToString(mLidOpenRotation));
        pw.println(prefix + "  mFixedToUserRotation=" + mFixedToUserRotation);
    }

    private class OrientationListener extends WindowOrientationListener {
@@ -945,4 +985,10 @@ public class DisplayRotation {
            }
        }
    }

    @VisibleForTesting
    interface ContentObserverRegister {
        void registerContentObserver(Uri uri, boolean notifyForDescendants,
                ContentObserver observer, @UserIdInt int userHandle);
    }
}
+18 −2
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ class DisplayWindowSettings {
        private boolean mShouldShowWithInsecureKeyguard = false;
        private boolean mShouldShowSystemDecors = false;
        private boolean mShouldShowIme = false;
        private boolean mFixedToUserRotation;

        private Entry(String name) {
            mName = name;
@@ -97,7 +98,8 @@ class DisplayWindowSettings {
                    && mRemoveContentMode == REMOVE_CONTENT_MODE_UNDEFINED
                    && !mShouldShowWithInsecureKeyguard
                    && !mShouldShowSystemDecors
                    && !mShouldShowIme;
                    && !mShouldShowIme
                    && !mFixedToUserRotation;
        }
    }

@@ -186,6 +188,13 @@ class DisplayWindowSettings {
        writeSettingsIfNeeded(entry, displayInfo);
    }

    void setFixedToUserRotation(DisplayContent displayContent, boolean fixedToUserRotation) {
        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
        final Entry entry = getOrCreateEntry(displayInfo);
        entry.mFixedToUserRotation = fixedToUserRotation;
        writeSettingsIfNeeded(entry, displayInfo);
    }

    private int getWindowingModeLocked(Entry entry, int displayId) {
        int windowingMode = entry != null ? entry.mWindowingMode
                : WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -331,7 +340,8 @@ class DisplayWindowSettings {
        displayInfo.overscanRight = entry.mOverscanRight;
        displayInfo.overscanBottom = entry.mOverscanBottom;

        dc.getDisplayRotation().restoreUserRotation(entry.mUserRotationMode, entry.mUserRotation);
        dc.getDisplayRotation().restoreSettings(entry.mUserRotationMode,
                entry.mUserRotation, entry.mFixedToUserRotation);

        if (entry.mForcedDensity != 0) {
            dc.mBaseDisplayDensity = entry.mForcedDensity;
@@ -458,6 +468,8 @@ class DisplayWindowSettings {
                    "shouldShowWithInsecureKeyguard");
            entry.mShouldShowSystemDecors = getBooleanAttribute(parser, "shouldShowSystemDecors");
            entry.mShouldShowIme = getBooleanAttribute(parser, "shouldShowIme");
            entry.mFixedToUserRotation = getBooleanAttribute(parser,
                    "fixedToUserRotation");
            mEntries.put(name, entry);
        }
        XmlUtils.skipCurrentTag(parser);
@@ -541,6 +553,10 @@ class DisplayWindowSettings {
                if (entry.mShouldShowIme) {
                    out.attribute(null, "shouldShowIme", Boolean.toString(entry.mShouldShowIme));
                }
                if (entry.mFixedToUserRotation) {
                    out.attribute(null, "fixedToUserRotation",
                            Boolean.toString(entry.mFixedToUserRotation));
                }
                out.endTag(null, "display");
            }

+2 −2
Original line number Diff line number Diff line
@@ -222,7 +222,7 @@ class ScreenRotationAnimation {
    }

    public ScreenRotationAnimation(Context context, DisplayContent displayContent,
            boolean forceDefaultOrientation, boolean isSecure, WindowManagerService service) {
            boolean fixedToUserRotation, boolean isSecure, WindowManagerService service) {
        mService = service;
        mContext = context;
        mDisplayContent = displayContent;
@@ -234,7 +234,7 @@ class ScreenRotationAnimation {
        final int originalWidth;
        final int originalHeight;
        DisplayInfo displayInfo = displayContent.getDisplayInfo();
        if (forceDefaultOrientation) {
        if (fixedToUserRotation) {
            // Emulated orientation.
            mForceDefaultOrientation = true;
            originalWidth = displayContent.mBaseDisplayWidth;
+12 −1
Original line number Diff line number Diff line
@@ -3577,6 +3577,17 @@ public class WindowManagerService extends IWindowManager.Stub
        }
    }

    void setRotateForApp(int displayId, boolean enabled) {
        synchronized (mGlobalLock) {
            final DisplayContent display = mRoot.getDisplayContent(displayId);
            if (display == null) {
                Slog.w(TAG, "Trying to set rotate for app for a missing display.");
                return;
            }
            display.getDisplayRotation().setFixedToUserRotation(enabled);
        }
    }

    @Override
    public void freezeRotation(int rotation) {
        freezeDisplayRotation(Display.DEFAULT_DISPLAY, rotation);
@@ -5383,7 +5394,7 @@ public class WindowManagerService extends IWindowManager.Stub

            displayContent.updateDisplayInfo();
            screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
                    displayContent.getDisplayRotation().isDefaultOrientationForced(), isSecure,
                    displayContent.getDisplayRotation().isFixedToUserRotation(), isSecure,
                    this);
            mAnimator.setScreenRotationAnimationLocked(mFrozenDisplayId,
                    screenRotationAnimation);
+30 −0
Original line number Diff line number Diff line
@@ -76,6 +76,8 @@ public class WindowManagerShellCommand extends ShellCommand {
                            getNextArgRequired());
                case "set-user-rotation":
                    return runSetDisplayUserRotation(pw);
                case "set-fix-to-user-rotation":
                    return runSetFixToUserRotation(pw);
                default:
                    return handleDefaultCommands(cmd);
            }
@@ -297,6 +299,32 @@ public class WindowManagerShellCommand extends ShellCommand {
        }
    }

    private int runSetFixToUserRotation(PrintWriter pw) {
        int displayId = Display.DEFAULT_DISPLAY;
        String arg = getNextArgRequired();
        if ("-d".equals(arg)) {
            displayId = Integer.parseInt(getNextArgRequired());
            arg = getNextArgRequired();
        }

        final boolean enabled;
        switch (arg) {
            case "enabled":
                enabled = true;
                break;
            case "disabled":
                enabled = false;
                break;
            default:
                getErrPrintWriter().println("Error: expecting enabled or disabled, but we get "
                        + arg);
                return -1;
        }

        mInternal.setRotateForApp(displayId, enabled);
        return 0;
    }

    @Override
    public void onHelp() {
        PrintWriter pw = getOutPrintWriter();
@@ -316,6 +344,8 @@ public class WindowManagerShellCommand extends ShellCommand {
        pw.println("    Dismiss the keyguard, prompting user for auth if necessary.");
        pw.println("  set-user-rotation [free|lock] [-d DISPLAY_ID] [rotation]");
        pw.println("    Set user rotation mode and user rotation.");
        pw.println("  set-fix-to-user-rotation [-d DISPLAY_ID] [enabled|disabled]");
        pw.println("    Enable or disable rotating display for app requested orientation.");
        if (!IS_USER) {
            pw.println("  tracing (start | stop)");
            pw.println("    Start or stop window tracing.");
Loading