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

Commit 95bb63c8 authored by petsjonkin's avatar petsjonkin
Browse files

Allow setting display mode without persisting it

Bug: b/375351220
Test: atest DisplayManagerSericeTest , manual testing: see bug comments
Flag: com.android.server.display.feature.flags.mode_switch_without_saving

Change-Id: I1612ca57900cff13fbee01100fdb2f0dbcb277e4
parent 738a4ab7
Loading
Loading
Loading
Loading
+27 −2
Original line number Diff line number Diff line
@@ -1219,11 +1219,36 @@ public final class DisplayManagerGlobal {

    /**
     * Sets the default display mode, according to the refresh rate and the resolution chosen by the
     * user.
     * user. Persists selected mode.
     * @hide
     */
    @RequiresPermission("android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE")
    public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) {
        setUserPreferredDisplayMode(displayId, mode, true);
    }

    /**
     * Sets the default display mode, according to the refresh rate and the resolution chosen by the
     * user. Allows to set display mode without persisting.
     * @hide
     */
    @RequiresPermission("android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE")
    public void setUserPreferredDisplayMode(int displayId, Display.Mode mode, boolean storeMode) {
        try {
            mDm.setUserPreferredDisplayMode(displayId, mode, storeMode);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /**
     * Resets the default display mode from persistence
     * @hide
     */
    @RequiresPermission("android.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE")
    public void resetUserPreferredDisplayMode(int displayId) {
        try {
            mDm.setUserPreferredDisplayMode(displayId, mode);
            mDm.resetUserPreferredDisplayMode(displayId);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
+3 −1
Original line number Diff line number Diff line
@@ -194,7 +194,9 @@ interface IDisplayManager {
    // Sets the user preferred display mode.
    // Requires MODIFY_USER_PREFERRED_DISPLAY_MODE permission.
    @EnforcePermission("MODIFY_USER_PREFERRED_DISPLAY_MODE")
    void setUserPreferredDisplayMode(int displayId, in Mode mode);
    void setUserPreferredDisplayMode(int displayId, in Mode mode, boolean storeMode);
    @EnforcePermission("MODIFY_USER_PREFERRED_DISPLAY_MODE")
    void resetUserPreferredDisplayMode(int displayId);
    Mode getUserPreferredDisplayMode(int displayId);
    Mode getSystemPreferredDisplayMode(int displayId);

+27 −1
Original line number Diff line number Diff line
@@ -1665,11 +1665,37 @@ public final class Display {
    @TestApi
    @RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
    public void setUserPreferredDisplayMode(@NonNull Display.Mode mode) {
        setUserPreferredDisplayMode(mode, true);
    }

    /**
     * Sets the default {@link Display.Mode} to use for the display.  The display mode includes
     * preference for resolution and refresh rate.
     * If the mode specified is not supported by the display, then no mode change occurs.
     *
     * @param mode The {@link Display.Mode} to set, which can include resolution and/or
     * refresh-rate. It is created using {@link Display.Mode.Builder}.
     * @param storeMode controls if the mode should be persisted or not.
     *`
     * @hide
     */
    @RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
    public void setUserPreferredDisplayMode(@NonNull Display.Mode mode, boolean storeMode) {
        // Create a new object containing default values for the unused fields like mode ID and
        // alternative refresh rates.
        Display.Mode preferredMode = new Display.Mode(mode.getPhysicalWidth(),
                mode.getPhysicalHeight(), mode.getRefreshRate());
        mGlobal.setUserPreferredDisplayMode(mDisplayId, preferredMode);
        mGlobal.setUserPreferredDisplayMode(mDisplayId, preferredMode, storeMode);
    }

    /**
     * Resets the default {@link Display.Mode} to use for the display from persistence.
     *`
     * @hide
     */
    @RequiresPermission(Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
    public void resetUserPreferredDisplayMode() {
        mGlobal.resetUserPreferredDisplayMode(mDisplayId);
    }

    /**
+103 −35
Original line number Diff line number Diff line
@@ -493,7 +493,7 @@ public final class DisplayManagerService extends SystemService {
    private final ArrayList<DisplayViewport> mViewports = new ArrayList<>();

    // Persistent data store for all internal settings maintained by the display manager service.
    private final PersistentDataStore mPersistentDataStore = new PersistentDataStore();
    private final PersistentDataStore mPersistentDataStore;

    // Temporary callback list, used when sending display events to applications.
    // May be used outside of the lock but only on the handler thread.
@@ -649,6 +649,7 @@ public final class DisplayManagerService extends SystemService {
        mHandler = new DisplayManagerHandler(displayThreadLooper);
        mHandlerExecutor = new HandlerExecutor(mHandler);
        mUiHandler = UiThread.getHandler();
        mPersistentDataStore = mInjector.getPersistentDataStore();
        mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
        mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
                foldSettingProvider,
@@ -2740,12 +2741,20 @@ public final class DisplayManagerService extends SystemService {
    }

    private void configurePreferredDisplayModeLocked(LogicalDisplay display) {
        final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
        final Point userPreferredResolution =
        DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
        Display.Mode mode = getStoredUserPreferredModeLocked(device);
        if (mode != null) {
            device.setUserPreferredDisplayModeLocked(mode);
        }
    }

    @Nullable
    private Display.Mode getStoredUserPreferredModeLocked(@Nullable DisplayDevice device) {
        Point userPreferredResolution =
                mPersistentDataStore.getUserPreferredResolution(device);
        final float refreshRate = mPersistentDataStore.getUserPreferredRefreshRate(device);
        float refreshRate = mPersistentDataStore.getUserPreferredRefreshRate(device);
        if (userPreferredResolution == null && Float.isNaN(refreshRate)) {
            return;
            return null;
        }
        Display.Mode.Builder modeBuilder = new Display.Mode.Builder();
        if (userPreferredResolution != null) {
@@ -2754,7 +2763,7 @@ public final class DisplayManagerService extends SystemService {
        if (!Float.isNaN(refreshRate)) {
            modeBuilder.setRefreshRate(refreshRate);
        }
        device.setUserPreferredDisplayModeLocked(modeBuilder.build());
        return modeBuilder.build();
    }

    @GuardedBy("mSyncRoot")
@@ -2837,33 +2846,80 @@ public final class DisplayManagerService extends SystemService {
        return mOverlayProperties;
    }

    void setUserPreferredDisplayModeInternal(int displayId, Display.Mode mode) {
    void resetUserPreferredDisplayModeInternal(int displayId) {
        if (!mFlags.isModeSwitchWithoutSavingEnabled()) {
            return;
        }
        synchronized (mSyncRoot) {
            Display.Mode mode;
            if (displayId == Display.INVALID_DISPLAY) {
                float refreshRate = Settings.Global.getFloat(mContext.getContentResolver(),
                        Settings.Global.USER_PREFERRED_REFRESH_RATE,
                        Display.INVALID_DISPLAY_REFRESH_RATE);
                int height = Settings.Global.getInt(mContext.getContentResolver(),
                        Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT,
                        Display.INVALID_DISPLAY_HEIGHT);
                int width = Settings.Global.getInt(mContext.getContentResolver(),
                        Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH,
                        Display.INVALID_DISPLAY_WIDTH);
                mode = new Display.Mode(width, height, refreshRate);
            } else {
                DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
                mode = getStoredUserPreferredModeLocked(displayDevice);
            }
            setUserPreferredDisplayModeInternal(displayId, mode, false);
        }
    }

    void setUserPreferredDisplayModeInternal(int displayId, @Nullable Display.Mode mode) {
        setUserPreferredDisplayModeInternal(displayId, mode, true);
    }

    void setUserPreferredDisplayModeInternal(
            int displayId, @Nullable Display.Mode mode, boolean storeMode) {
        synchronized (mSyncRoot) {
            if (mode != null && !isResolutionAndRefreshRateValid(mode)
                    && displayId == Display.INVALID_DISPLAY) {
                throw new IllegalArgumentException("width, height and refresh rate of mode should "
                        + "be greater than 0 when setting the global user preferred display mode.");
            }

            final int resolutionHeight = mode == null ? Display.INVALID_DISPLAY_HEIGHT
                    : mode.getPhysicalHeight();
            final int resolutionWidth = mode == null ? Display.INVALID_DISPLAY_WIDTH
                    : mode.getPhysicalWidth();
            final float refreshRate = mode == null ? Display.INVALID_DISPLAY_REFRESH_RATE
                    : mode.getRefreshRate();

            storeModeInPersistentDataStoreLocked(
                    displayId, resolutionWidth, resolutionHeight, refreshRate);
            DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
            if (displayDevice == null) {
                return;
            }
            if (!mFlags.isModeSwitchWithoutSavingEnabled()) {
                storeMode = true;
            }
            if (storeMode) {
                storeModeLocked(displayId, mode);
            }
            if (displayId != Display.INVALID_DISPLAY) {
                setUserPreferredModeForDisplayLocked(displayId, mode);
            } else {
                mUserPreferredMode = mode;
                storeModeInGlobalSettingsLocked(
                        resolutionWidth, resolutionHeight, refreshRate, mode);
                mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
                    device.setUserPreferredDisplayModeLocked(mode);
                });
            }
        }
    }

    void  storeModeLocked(int displayId, @Nullable Display.Mode mode) {
        int resolutionHeight = mode == null ? Display.INVALID_DISPLAY_HEIGHT
                : mode.getPhysicalHeight();
        int resolutionWidth = mode == null ? Display.INVALID_DISPLAY_WIDTH
                : mode.getPhysicalWidth();
        float refreshRate = mode == null ? Display.INVALID_DISPLAY_REFRESH_RATE
                : mode.getRefreshRate();
        if (displayId == Display.INVALID_DISPLAY) {
            storeModeInGlobalSettingsLocked(
                    resolutionWidth, resolutionHeight, refreshRate);
        } else {
            storeModeInPersistentDataStoreLocked(displayId,
                    resolutionWidth, resolutionHeight, refreshRate);
        }
    }

    private void storeModeInPersistentDataStoreLocked(int displayId, int resolutionWidth,
            int resolutionHeight, float refreshRate) {
        DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
@@ -2877,13 +2933,6 @@ public final class DisplayManagerService extends SystemService {
        } finally {
            mPersistentDataStore.saveIfNeeded();
        }
    }

    private void setUserPreferredModeForDisplayLocked(int displayId, Display.Mode mode) {
        DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
        if (displayDevice == null) {
            return;
        }

        // We do not yet support backup and restore for our PersistentDataStore, however, we want to
        // preserve the user's choice for HIGH/FULL resolution setting, so we when we are given a
@@ -2896,7 +2945,7 @@ public final class DisplayManagerService extends SystemService {
            //     more than two resolutions using explicit mode enums long-term.
            Point[] resolutions = displayDevice.getSupportedResolutionsLocked();
            if (resolutions.length == 2) {
                Point newMode = new Point(mode.getPhysicalWidth(), mode.getPhysicalHeight());
                Point newMode = new Point(resolutionWidth, resolutionHeight);
                int resolutionMode = newMode.equals(resolutions[0]) ? RESOLUTION_MODE_HIGH
                        : newMode.equals(resolutions[1]) ? RESOLUTION_MODE_FULL
                                : RESOLUTION_MODE_UNKNOWN;
@@ -2905,21 +2954,23 @@ public final class DisplayManagerService extends SystemService {
                        UserHandle.USER_CURRENT);
            }
        }
    }

    private void setUserPreferredModeForDisplayLocked(int displayId, Display.Mode mode) {
        DisplayDevice displayDevice = getDeviceForDisplayLocked(displayId);
        if (displayDevice != null) {
            displayDevice.setUserPreferredDisplayModeLocked(mode);
        }
    }

    private void storeModeInGlobalSettingsLocked(
            int resolutionWidth, int resolutionHeight, float refreshRate, Display.Mode mode) {
            int resolutionWidth, int resolutionHeight, float refreshRate) {
        Settings.Global.putFloat(mContext.getContentResolver(),
                Settings.Global.USER_PREFERRED_REFRESH_RATE, refreshRate);
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.USER_PREFERRED_RESOLUTION_HEIGHT, resolutionHeight);
        Settings.Global.putInt(mContext.getContentResolver(),
                Settings.Global.USER_PREFERRED_RESOLUTION_WIDTH, resolutionWidth);
        mDisplayDeviceRepo.forEachLocked((DisplayDevice device) -> {
            device.setUserPreferredDisplayModeLocked(mode);
        });
    }

    /**
@@ -4060,6 +4111,10 @@ public final class DisplayManagerService extends SystemService {
        boolean canInternalDisplayHostDesktops(Context context) {
            return DesktopModeHelper.canInternalDisplayHostDesktops(context);
        }

        PersistentDataStore getPersistentDataStore() {
            return new PersistentDataStore();
        }
    }

    @VisibleForTesting
@@ -5400,11 +5455,24 @@ public final class DisplayManagerService extends SystemService {

        @EnforcePermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
        @Override // Binder call
        public void setUserPreferredDisplayMode(int displayId, Display.Mode mode) {
        public void setUserPreferredDisplayMode(int displayId, Display.Mode mode,
                boolean storeMode) {
            setUserPreferredDisplayMode_enforcePermission();
            final long token = Binder.clearCallingIdentity();
            try {
                setUserPreferredDisplayModeInternal(displayId, mode);
                setUserPreferredDisplayModeInternal(displayId, mode, storeMode);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @EnforcePermission(android.Manifest.permission.MODIFY_USER_PREFERRED_DISPLAY_MODE)
        @Override // Binder call
        public void resetUserPreferredDisplayMode(int displayId) {
            resetUserPreferredDisplayMode_enforcePermission();
            final long token = Binder.clearCallingIdentity();
            try {
                resetUserPreferredDisplayModeInternal(displayId);
            } finally {
                Binder.restoreCallingIdentity(token);
            }
+35 −2
Original line number Diff line number Diff line
@@ -86,6 +86,8 @@ class DisplayManagerShellCommand extends ShellCommand {
                return setAmbientColorTemperatureOverride();
            case "set-user-preferred-display-mode":
                return setUserPreferredDisplayMode();
            case "reset-user-preferred-display-mode":
                return resetUserPreferredDisplayMode();
            case "clear-user-preferred-display-mode":
                return clearUserPreferredDisplayMode();
            case "get-user-preferred-display-mode":
@@ -163,7 +165,17 @@ class DisplayManagerShellCommand extends ShellCommand {
        pw.println("  dwb-set-cct CCT");
        pw.println("    Sets the ambient color temperature override to CCT (use -1 to disable).");
        pw.println("  set-user-preferred-display-mode WIDTH HEIGHT REFRESH-RATE "
                + "DISPLAY_ID (optional)");
                + "DISPLAY_ID (optional) STORE_MODE (optional)");
        pw.println("    Sets the user preferred display mode which has fields WIDTH, HEIGHT and "
                + "REFRESH-RATE. If DISPLAY_ID is passed, the mode change is applied to display"
                + "with id = DISPLAY_ID, if DISPLAY_ID == -1 or missing change is applied globally."
                + " If STORE_MODE is true or missing, mode will be persisted, otherwise it will be"
                + "applied without persisting. Should be used only together with DISPLAY_ID.");
        pw.println("  reset-user-preferred-display-mode DISPLAY_ID (optional)");
        pw.println("    Resets the user preferred display mode with stored mode. "
                + "If DISPLAY_ID is passed, the persisted mode is applied to display with "
                + "id = DISPLAY_ID, if DISPLAY_ID == -1 or missing persisted mode "
                + "is applied globally.");
        pw.println("    Sets the user preferred display mode which has fields WIDTH, HEIGHT and "
                + "REFRESH-RATE. If DISPLAY_ID is passed, the mode change is applied to display"
                + "with id = DISPLAY_ID, else mode change is applied globally.");
@@ -492,8 +504,29 @@ class DisplayManagerShellCommand extends ShellCommand {
                return 1;
            }
        }
        final String storeModeText = getNextArg();
        boolean storeMode = true;
        if (storeModeText != null) {
            storeMode = Boolean.parseBoolean(storeModeText);
        }

        mService.setUserPreferredDisplayModeInternal(
                displayId, new Display.Mode(width, height, refreshRate));
                displayId, new Display.Mode(width, height, refreshRate), storeMode);
        return 0;
    }

    private int resetUserPreferredDisplayMode() {
        final String displayIdText = getNextArg();
        int displayId = Display.INVALID_DISPLAY;
        if (displayIdText != null) {
            try {
                displayId = Integer.parseInt(displayIdText);
            } catch (NumberFormatException e) {
                getErrPrintWriter().println("Error: invalid format of display ID");
                return 1;
            }
        }
        mService.resetUserPreferredDisplayModeInternal(displayId);
        return 0;
    }

Loading