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

Commit bf780c6c authored by Oleg Blinnikov's avatar Oleg Blinnikov Committed by Android (Google) Code Review
Browse files

Merge "User refresh rate for external display" into main

parents 3b0072a7 b59ef4fb
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -212,6 +212,10 @@ public class DisplayManagerFlags {
            Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE,
            Flags::blockAutobrightnessChangesOnStylusUsage
    );
    private final FlagState mIsUserRefreshRateForExternalDisplayEnabled = new FlagState(
            Flags.FLAG_ENABLE_USER_REFRESH_RATE_FOR_EXTERNAL_DISPLAY,
            Flags::enableUserRefreshRateForExternalDisplay
    );

    private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState(
            Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS,
@@ -455,6 +459,14 @@ public class DisplayManagerFlags {
        return mBlockAutobrightnessChangesOnStylusUsage.isEnabled();
    }

    /**
     * @return {@code true} if need to use user refresh rate settings for
     * external displays.
     */
    public boolean isUserRefreshRateForExternalDisplayEnabled() {
        return mIsUserRefreshRateForExternalDisplayEnabled.isEnabled();
    }

    /**
     * dumps all flagstates
     * @param pw printWriter
@@ -501,6 +513,7 @@ public class DisplayManagerFlags {
        pw.println(" " + mIdleScreenConfigInSubscribingLightSensor);
        pw.println(" " + mEnableBatteryStatsForAllDisplays);
        pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage);
        pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled);
    }

    private static class FlagState {
+11 −0
Original line number Diff line number Diff line
@@ -381,3 +381,14 @@ flag {
    bug: "352411468"
    is_fixed_read_only: true
}

flag {
    name: "enable_user_refresh_rate_for_external_display"
    namespace: "display_manager"
    description: "Apply refresh rate from user preferred display mode to external displays"
    bug: "370657357"
    is_fixed_read_only: true
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}
+56 −25
Original line number Diff line number Diff line
@@ -1194,6 +1194,13 @@ public class DisplayModeDirector {
        @GuardedBy("mLock")
        private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
                float defaultRefreshRate, int displayId) {
            if (mDisplayObserver.isExternalDisplayLocked(displayId)) {
                if (mLoggingEnabled) {
                    Slog.d(TAG, "skip updateRefreshRateSettingLocked for external display "
                            + displayId);
                }
                return;
            }
            // 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
@@ -1243,6 +1250,8 @@ public class DisplayModeDirector {
        }

        private void removeRefreshRateSetting(int displayId) {
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_REFRESH_RATE,
                    null);
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
                    null);
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
@@ -1458,11 +1467,11 @@ public class DisplayModeDirector {
        public void onDisplayAdded(int displayId) {
            updateDisplayDeviceConfig(displayId);
            DisplayInfo displayInfo = getDisplayInfo(displayId);
            registerExternalDisplay(displayInfo);
            updateDisplayModes(displayId, displayInfo);
            updateLayoutLimitedFrameRate(displayId, displayInfo);
            updateUserSettingDisplayPreferredSize(displayInfo);
            updateDisplaysPeakRefreshRateAndResolution(displayInfo);
            addDisplaysSynchronizedPeakRefreshRate(displayInfo);
        }

        @Override
@@ -1477,7 +1486,7 @@ public class DisplayModeDirector {
            updateLayoutLimitedFrameRate(displayId, null);
            removeUserSettingDisplayPreferredSize(displayId);
            removeDisplaysPeakRefreshRateAndResolution(displayId);
            removeDisplaysSynchronizedPeakRefreshRate(displayId);
            unregisterExternalDisplay(displayId);
        }

        @Override
@@ -1489,6 +1498,30 @@ public class DisplayModeDirector {
            updateUserSettingDisplayPreferredSize(displayInfo);
        }

        private void registerExternalDisplay(DisplayInfo displayInfo) {
            if (displayInfo == null || displayInfo.type != Display.TYPE_EXTERNAL) {
                return;
            }
            synchronized (mLock) {
                mExternalDisplaysConnected.add(displayInfo.displayId);
                if (mExternalDisplaysConnected.size() == 1) {
                    addDisplaysSynchronizedPeakRefreshRate();
                }
            }
        }

        private void unregisterExternalDisplay(int displayId) {
            synchronized (mLock) {
                if (!isExternalDisplayLocked(displayId)) {
                    return;
                }
                mExternalDisplaysConnected.remove(displayId);
                if (mExternalDisplaysConnected.isEmpty()) {
                    removeDisplaysSynchronizedPeakRefreshRate();
                }
            }
        }

        boolean isExternalDisplayLocked(int displayId) {
            return mExternalDisplaysConnected.contains(displayId);
        }
@@ -1534,11 +1567,25 @@ public class DisplayModeDirector {
                return;
            }

            if (info.type == Display.TYPE_EXTERNAL
                    && mDisplayManagerFlags.isUserRefreshRateForExternalDisplayEnabled()
                    && !isRefreshRateSynchronizationEnabled()) {
                mVotesStorage.updateVote(info.displayId,
                        Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
                        Vote.forSizeAndPhysicalRefreshRatesRange(
                                /* minWidth */ preferredMode.getPhysicalWidth(),
                                /* minHeight */ preferredMode.getPhysicalHeight(),
                                /* width */ preferredMode.getPhysicalWidth(),
                                /* height */ preferredMode.getPhysicalHeight(),
                                /* minRefreshRate */ preferredMode.getRefreshRate(),
                                /* maxRefreshRate */ preferredMode.getRefreshRate()));
            } else {
                mVotesStorage.updateVote(info.displayId,
                        Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
                        Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
                                /* height */ preferredMode.getPhysicalHeight()));
            }
        }

        @Nullable
        private Display.Mode findDisplayPreferredMode(@NonNull DisplayInfo info) {
@@ -1584,17 +1631,10 @@ public class DisplayModeDirector {
         * Sets 60Hz target refresh rate as the vote with
         * {@link Vote#PRIORITY_SYNCHRONIZED_REFRESH_RATE} priority.
         */
        private void addDisplaysSynchronizedPeakRefreshRate(@Nullable final DisplayInfo info) {
            if (info == null || info.type != Display.TYPE_EXTERNAL
                    || !isRefreshRateSynchronizationEnabled()) {
                return;
            }
            synchronized (mLock) {
                mExternalDisplaysConnected.add(info.displayId);
                if (mExternalDisplaysConnected.size() != 1) {
        private void addDisplaysSynchronizedPeakRefreshRate() {
            if (!isRefreshRateSynchronizationEnabled()) {
                return;
            }
            }
            // set minRefreshRate as the max refresh rate.
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE,
                    Vote.forPhysicalRefreshRates(
@@ -1610,19 +1650,10 @@ public class DisplayModeDirector {
                                    + SYNCHRONIZED_REFRESH_RATE_TOLERANCE));
        }

        private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) {
        private void removeDisplaysSynchronizedPeakRefreshRate() {
            if (!isRefreshRateSynchronizationEnabled()) {
                return;
            }
            synchronized (mLock) {
                if (!isExternalDisplayLocked(displayId)) {
                    return;
                }
                mExternalDisplaysConnected.remove(displayId);
                if (!mExternalDisplaysConnected.isEmpty()) {
                    return;
                }
            }
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_REFRESH_RATE, null);
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null);
        }
+1 −1
Original line number Diff line number Diff line
@@ -44,7 +44,7 @@ interface Vote {
    // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
    int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;

    // User setting preferred display resolution.
    // User setting preferred display resolution, for external displays also includes refresh rate.
    int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4;

    // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
+59 −2
Original line number Diff line number Diff line
@@ -1871,6 +1871,60 @@ public class DisplayModeDirectorTest {
                /* frameRateHigh= */ peakRefreshRate);
    }

    @Test
    public void testPeakRefreshRate_notAppliedToExternalDisplays() {
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
                .thenReturn(true);
        mInjector.mDisplayInfo.type = Display.TYPE_EXTERNAL;
        DisplayModeDirector director =
                new DisplayModeDirector(mContext, mHandler, mInjector,
                        mDisplayManagerFlags, mDisplayDeviceConfigProvider);
        director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
        director.getDisplayObserver().onDisplayAdded(DISPLAY_ID);
        director.getDisplayObserver().onDisplayAdded(DISPLAY_ID_2);

        Display.Mode[] modes1 = new Display.Mode[] {
                new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
                        /* refreshRate= */ 60),
                new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
                        /* refreshRate= */ 130),
        };
        Display.Mode[] modes2 = new Display.Mode[] {
                new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
                        /* refreshRate= */ 60),
                new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
                        /* refreshRate= */ 140),
        };
        SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
        supportedModesByDisplay.put(DISPLAY_ID, modes1);
        supportedModesByDisplay.put(DISPLAY_ID_2, modes2);

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

        // Disable Smooth Display
        setPeakRefreshRate(RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE);

        Vote vote1 = director.getVote(DISPLAY_ID,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        Vote vote2 = director.getVote(DISPLAY_ID_2,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertThat(vote1).isNull();
        assertThat(vote2).isNull();

        // Enable Smooth Display
        setPeakRefreshRate(Float.POSITIVE_INFINITY);

        vote1 = director.getVote(DISPLAY_ID,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        vote2 = director.getVote(DISPLAY_ID_2,
                Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
        assertThat(vote1).isNull();
        assertThat(vote2).isNull();
    }

    @Test
    public void testPeakRefreshRate_DisplayChanged() {
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
@@ -1968,8 +2022,9 @@ public class DisplayModeDirectorTest {
    @Test
    @Parameters({
        "true, true, 60",
        "false, true, 50",
        "true, false, 50"
        "false, true, 60",
        "true, false, 50",
        "false, false, 50"
    })
    public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled,
            boolean isExternalDisplay, float expectedMaxRenderFrameRate) {
@@ -3810,6 +3865,7 @@ public class DisplayModeDirectorTest {
                SensorManagerInternal sensorManagerInternal) {
            mDeviceConfig = new FakeDeviceConfig();
            mDisplayInfo = new DisplayInfo();
            mDisplayInfo.type = Display.TYPE_INTERNAL;
            mDisplayInfo.defaultModeId = MODE_ID;
            mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
                    800, 600, /* refreshRate= */ 60)};
@@ -3856,6 +3912,7 @@ public class DisplayModeDirectorTest {
        @Override
        public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
            displayInfo.copyFrom(mDisplayInfo);
            displayInfo.displayId = displayId;
            return mDisplayInfoValid;
        }

Loading