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

Commit c1a0e1f6 authored by Piotr Wilczyński's avatar Piotr Wilczyński
Browse files

Min and max refresh rate per display

- In onDisplayChanged, update the min and peak refresh rates for this display.

- When Smooth Display or Force Peak Refresh Rate are turned on/off, update the min and peak refresh rates for all the displays.

Bug: 273298889
Test: atest DisplayModeDirectorTest
Test: atest RefreshRateSettingsUtilsTest
Change-Id: I6a6e280c34500cf7164d9b32d79dcd9d5ff7d52a
parent 813da462
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -37,11 +37,22 @@ public class RefreshRateSettingsUtils {
     * @return The highest refresh rate
     */
    public static float findHighestRefreshRateForDefaultDisplay(Context context) {
        return findHighestRefreshRate(context, Display.DEFAULT_DISPLAY);
    }

    /**
     * Find the highest refresh rate among all the modes of the specified display.
     *
     * @param context The context
     * @param displayId The display ID
     * @return The highest refresh rate
     */
    public static float findHighestRefreshRate(Context context, int displayId) {
        final DisplayManager dm = context.getSystemService(DisplayManager.class);
        final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
        final Display display = dm.getDisplay(displayId);

        if (display == null) {
            Log.w(TAG, "No valid default display device");
            Log.w(TAG, "No valid display device with ID = " + displayId);
            return DEFAULT_REFRESH_RATE;
        }

+32 −10
Original line number Diff line number Diff line
@@ -21,8 +21,8 @@ import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT
import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
import static android.view.Display.Mode.INVALID_MODE_ID;

import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRate;
import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE;
import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay;

import android.annotation.IntegerRes;
import android.annotation.NonNull;
@@ -957,12 +957,17 @@ public class DisplayModeDirector {
        return mHbmObserver;
    }

    @VisibleForTesting
    DisplayObserver getDisplayObserver() {
        return mDisplayObserver;
    }

    @VisibleForTesting
    DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
            float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
        synchronized (mLock) {
            mSettingsObserver.updateRefreshRateSettingLocked(
                    minRefreshRate, peakRefreshRate, defaultRefreshRate);
            mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate,
                    defaultRefreshRate, Display.DEFAULT_DISPLAY);
            return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY);
        }
    }
@@ -1296,9 +1301,23 @@ public class DisplayModeDirector {
            mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
        }

        /**
         * Update refresh rate settings for all displays
         */
        private void updateRefreshRateSettingLocked() {
            Display[] displays = mInjector.getDisplays();
            for (int i = 0; i < displays.length; i++) {
                updateRefreshRateSettingLocked(displays[i].getDisplayId());
            }
        }

        /**
         * Update refresh rate settings for a specific display
         * @param displayId The display ID
         */
        private void updateRefreshRateSettingLocked(int displayId) {
            final ContentResolver cr = mContext.getContentResolver();
            float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext);
            float highestRefreshRate = findHighestRefreshRate(mContext, displayId);

            float minRefreshRate = Settings.System.getFloatForUser(cr,
                    Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
@@ -1326,11 +1345,12 @@ public class DisplayModeDirector {
                }
            }

            updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
            updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate,
                    displayId);
        }

        private void updateRefreshRateSettingLocked(
                float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
        private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
                float defaultRefreshRate, int displayId) {
            // TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
            // used to predict if we're going to be doing frequent refresh rate switching, and if
            // so, enable the brightness observer. The logic here is more complicated and fragile
@@ -1338,9 +1358,9 @@ public class DisplayModeDirector {
            Vote peakVote = peakRefreshRate == 0f
                    ? null
                    : Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate));
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
                    peakVote);
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
                    Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY));
            Vote defaultVote =
                    defaultRefreshRate == 0f
@@ -1497,7 +1517,8 @@ public class DisplayModeDirector {
        }
    }

    private final class DisplayObserver implements DisplayManager.DisplayListener {
    @VisibleForTesting
    public final class DisplayObserver implements DisplayManager.DisplayListener {
        // Note that we can never call into DisplayManager or any of the non-POD classes it
        // returns, while holding mLock since it may call into DMS, which might be simultaneously
        // calling into us already holding its own lock.
@@ -1589,6 +1610,7 @@ public class DisplayModeDirector {
            updateDisplayModes(displayId, displayInfo);
            updateLayoutLimitedFrameRate(displayId, displayInfo);
            updateUserSettingDisplayPreferredSize(displayInfo);
            mSettingsObserver.updateRefreshRateSettingLocked(displayId);
        }

        @Nullable
+16 −3
Original line number Diff line number Diff line
@@ -72,14 +72,27 @@ public class RefreshRateSettingsUtilsTest {

    @Test
    public void testFindHighestRefreshRateForDefaultDisplay() {
        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
        assertEquals(DEFAULT_REFRESH_RATE,
        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
        assertEquals(120,
                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
                /* delta= */ 0);
    }

        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
    @Test
    public void testFindHighestRefreshRate() {
        int displayId = 13;
        when(mDisplayManagerMock.getDisplay(displayId)).thenReturn(mDisplayMock);
        assertEquals(120,
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, displayId),
                /* delta= */ 0);
    }

    @Test
    public void testFindHighestRefreshRate_DisplayIsNull() {
        when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
        assertEquals(DEFAULT_REFRESH_RATE,
                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
                /* delta= */ 0);

    }
}
+98 −20
Original line number Diff line number Diff line
@@ -279,6 +279,7 @@ public class DisplayModeDirectorTest {
    };

    private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY;
    private static final int DISPLAY_ID_2 = Display.DEFAULT_DISPLAY + 1;
    private static final int MODE_ID = 1;
    private static final float TRANSITION_POINT = 0.763f;

@@ -1525,9 +1526,12 @@ public class DisplayModeDirectorTest {
    public void testPeakRefreshRate_FlagEnabled() {
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                .thenReturn(true);
        float highestRefreshRate = 130;
        doReturn(highestRefreshRate).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
        float highestRefreshRate1 = 130;
        float highestRefreshRate2 = 132;
        doReturn(highestRefreshRate1).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
        doReturn(highestRefreshRate2).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID_2));
        DisplayModeDirector director =
                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -1538,10 +1542,14 @@ public class DisplayModeDirectorTest {

        setPeakRefreshRate(Float.POSITIVE_INFINITY);

        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
        Vote vote1 = director.getVote(DISPLAY_ID,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
                highestRefreshRate);
        Vote vote2 = director.getVote(DISPLAY_ID_2,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 0,
                /* frameRateHigh= */ highestRefreshRate1);
        assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 0,
                /* frameRateHigh= */ highestRefreshRate2);
    }

    @Test
@@ -1559,19 +1567,54 @@ public class DisplayModeDirectorTest {

        setPeakRefreshRate(peakRefreshRate);

        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
                peakRefreshRate);
        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
                /* frameRateHigh= */ peakRefreshRate);
    }

    @Test
    public void testMinRefreshRate_FlagEnabled() {
    public void testPeakRefreshRate_DisplayChanged() {
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                .thenReturn(true);
        float highestRefreshRate = 130;
        doReturn(highestRefreshRate).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
        DisplayModeDirector director =
                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);

        Sensor lightSensor = createLightSensor();
        SensorManager sensorManager = createMockSensorManager(lightSensor);
        director.start(sensorManager);

        setPeakRefreshRate(Float.POSITIVE_INFINITY);

        Vote vote = director.getVote(DISPLAY_ID,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
                /* frameRateHigh= */ highestRefreshRate);

        // The highest refresh rate of the display changes
        highestRefreshRate = 140;
        doReturn(highestRefreshRate).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
        director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);

        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
                /* frameRateHigh= */ highestRefreshRate);
    }

    @Test
    public void testMinRefreshRate_FlagEnabled() {
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                .thenReturn(true);
        float highestRefreshRate1 = 130;
        float highestRefreshRate2 = 132;
        doReturn(highestRefreshRate1).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
        doReturn(highestRefreshRate2).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID_2));
        DisplayModeDirector director =
                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
@@ -1582,9 +1625,12 @@ public class DisplayModeDirectorTest {

        setMinRefreshRate(Float.POSITIVE_INFINITY);

        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
        Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
        Vote vote2 = director.getVote(DISPLAY_ID_2,
                Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
        assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ highestRefreshRate1,
                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
        assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ highestRefreshRate2,
                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
    }

@@ -1603,12 +1649,43 @@ public class DisplayModeDirectorTest {

        setMinRefreshRate(minRefreshRate);

        Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
                Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate,
                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
    }

    @Test
    public void testMinRefreshRate_DisplayChanged() {
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                .thenReturn(true);
        float highestRefreshRate = 130;
        doReturn(highestRefreshRate).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
        DisplayModeDirector director =
                createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);

        Sensor lightSensor = createLightSensor();
        SensorManager sensorManager = createMockSensorManager(lightSensor);
        director.start(sensorManager);

        setMinRefreshRate(Float.POSITIVE_INFINITY);

        Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
                /* frameRateHigh= */ Float.POSITIVE_INFINITY);

        // The highest refresh rate of the display changes
        highestRefreshRate = 140;
        doReturn(highestRefreshRate).when(() ->
                RefreshRateSettingsUtils.findHighestRefreshRate(mContext, DISPLAY_ID));
        director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);

        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
        assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
                /* frameRateHigh= */ Float.POSITIVE_INFINITY);
    }

    @Test
    public void testSensorRegistration() {
        // First, configure brightness zones or DMD won't register for sensor data.
@@ -3356,7 +3433,7 @@ public class DisplayModeDirectorTest {
    public static class FakesInjector implements DisplayModeDirector.Injector {
        private final FakeDeviceConfig mDeviceConfig;
        private final DisplayInfo mDisplayInfo;
        private final Display mDisplay;
        private final Map<Integer, Display> mDisplays;
        private boolean mDisplayInfoValid = true;
        private final DisplayManagerInternal mDisplayManagerInternal;
        private final StatusBarManagerInternal mStatusBarManagerInternal;
@@ -3377,7 +3454,8 @@ public class DisplayModeDirectorTest {
            mDisplayInfo.defaultModeId = MODE_ID;
            mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
                    800, 600, /* refreshRate= */ 60)};
            mDisplay = createDisplay(DISPLAY_ID);
            mDisplays = Map.of(DISPLAY_ID, createDisplay(DISPLAY_ID),
                    DISPLAY_ID_2, createDisplay(DISPLAY_ID_2));
            mDisplayManagerInternal = displayManagerInternal;
            mStatusBarManagerInternal = statusBarManagerInternal;
            mSensorManagerInternal = sensorManagerInternal;
@@ -3408,12 +3486,12 @@ public class DisplayModeDirectorTest {

        @Override
        public Display getDisplay(int displayId) {
            return mDisplay;
            return mDisplays.get(displayId);
        }

        @Override
        public Display[] getDisplays() {
            return new Display[] { mDisplay };
            return mDisplays.values().toArray(new Display[0]);
        }

        @Override