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 Original line Diff line number Diff line
@@ -212,6 +212,10 @@ public class DisplayManagerFlags {
            Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE,
            Flags.FLAG_BLOCK_AUTOBRIGHTNESS_CHANGES_ON_STYLUS_USAGE,
            Flags::blockAutobrightnessChangesOnStylusUsage
            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(
    private final FlagState mEnableBatteryStatsForAllDisplays = new FlagState(
            Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS,
            Flags.FLAG_ENABLE_BATTERY_STATS_FOR_ALL_DISPLAYS,
@@ -455,6 +459,14 @@ public class DisplayManagerFlags {
        return mBlockAutobrightnessChangesOnStylusUsage.isEnabled();
        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
     * dumps all flagstates
     * @param pw printWriter
     * @param pw printWriter
@@ -501,6 +513,7 @@ public class DisplayManagerFlags {
        pw.println(" " + mIdleScreenConfigInSubscribingLightSensor);
        pw.println(" " + mIdleScreenConfigInSubscribingLightSensor);
        pw.println(" " + mEnableBatteryStatsForAllDisplays);
        pw.println(" " + mEnableBatteryStatsForAllDisplays);
        pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage);
        pw.println(" " + mBlockAutobrightnessChangesOnStylusUsage);
        pw.println(" " + mIsUserRefreshRateForExternalDisplayEnabled);
    }
    }


    private static class FlagState {
    private static class FlagState {
+11 −0
Original line number Original line Diff line number Diff line
@@ -381,3 +381,14 @@ flag {
    bug: "352411468"
    bug: "352411468"
    is_fixed_read_only: true
    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 Original line Diff line number Diff line
@@ -1194,6 +1194,13 @@ public class DisplayModeDirector {
        @GuardedBy("mLock")
        @GuardedBy("mLock")
        private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
        private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
                float defaultRefreshRate, int displayId) {
                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
            // 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
            // 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
            // 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) {
        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,
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
                    null);
                    null);
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
            mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
@@ -1458,11 +1467,11 @@ public class DisplayModeDirector {
        public void onDisplayAdded(int displayId) {
        public void onDisplayAdded(int displayId) {
            updateDisplayDeviceConfig(displayId);
            updateDisplayDeviceConfig(displayId);
            DisplayInfo displayInfo = getDisplayInfo(displayId);
            DisplayInfo displayInfo = getDisplayInfo(displayId);
            registerExternalDisplay(displayInfo);
            updateDisplayModes(displayId, displayInfo);
            updateDisplayModes(displayId, displayInfo);
            updateLayoutLimitedFrameRate(displayId, displayInfo);
            updateLayoutLimitedFrameRate(displayId, displayInfo);
            updateUserSettingDisplayPreferredSize(displayInfo);
            updateUserSettingDisplayPreferredSize(displayInfo);
            updateDisplaysPeakRefreshRateAndResolution(displayInfo);
            updateDisplaysPeakRefreshRateAndResolution(displayInfo);
            addDisplaysSynchronizedPeakRefreshRate(displayInfo);
        }
        }


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


        @Override
        @Override
@@ -1489,6 +1498,30 @@ public class DisplayModeDirector {
            updateUserSettingDisplayPreferredSize(displayInfo);
            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) {
        boolean isExternalDisplayLocked(int displayId) {
            return mExternalDisplaysConnected.contains(displayId);
            return mExternalDisplaysConnected.contains(displayId);
        }
        }
@@ -1534,11 +1567,25 @@ public class DisplayModeDirector {
                return;
                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,
                mVotesStorage.updateVote(info.displayId,
                        Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
                        Vote.PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE,
                        Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
                        Vote.forSize(/* width */ preferredMode.getPhysicalWidth(),
                                /* height */ preferredMode.getPhysicalHeight()));
                                /* height */ preferredMode.getPhysicalHeight()));
            }
            }
        }


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


        private void removeDisplaysSynchronizedPeakRefreshRate(final int displayId) {
        private void removeDisplaysSynchronizedPeakRefreshRate() {
            if (!isRefreshRateSynchronizationEnabled()) {
            if (!isRefreshRateSynchronizationEnabled()) {
                return;
                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_REFRESH_RATE, null);
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null);
            mVotesStorage.updateGlobalVote(Vote.PRIORITY_SYNCHRONIZED_RENDER_FRAME_RATE, null);
        }
        }
+1 −1
Original line number Original line Diff line number Diff line
@@ -44,7 +44,7 @@ interface Vote {
    // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
    // It votes [minRefreshRate, Float.POSITIVE_INFINITY]
    int PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE = 3;
    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;
    int PRIORITY_USER_SETTING_DISPLAY_PREFERRED_SIZE = 4;


    // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
    // APP_REQUEST_RENDER_FRAME_RATE_RANGE is used to for internal apps to limit the render
+59 −2
Original line number Original line Diff line number Diff line
@@ -1871,6 +1871,60 @@ public class DisplayModeDirectorTest {
                /* frameRateHigh= */ peakRefreshRate);
                /* 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
    @Test
    public void testPeakRefreshRate_DisplayChanged() {
    public void testPeakRefreshRate_DisplayChanged() {
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
        when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
@@ -1968,8 +2022,9 @@ public class DisplayModeDirectorTest {
    @Test
    @Test
    @Parameters({
    @Parameters({
        "true, true, 60",
        "true, true, 60",
        "false, true, 50",
        "false, true, 60",
        "true, false, 50"
        "true, false, 50",
        "false, false, 50"
    })
    })
    public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled,
    public void testExternalDisplayMaxRefreshRate(boolean isRefreshRateSynchronizationEnabled,
            boolean isExternalDisplay, float expectedMaxRenderFrameRate) {
            boolean isExternalDisplay, float expectedMaxRenderFrameRate) {
@@ -3810,6 +3865,7 @@ public class DisplayModeDirectorTest {
                SensorManagerInternal sensorManagerInternal) {
                SensorManagerInternal sensorManagerInternal) {
            mDeviceConfig = new FakeDeviceConfig();
            mDeviceConfig = new FakeDeviceConfig();
            mDisplayInfo = new DisplayInfo();
            mDisplayInfo = new DisplayInfo();
            mDisplayInfo.type = Display.TYPE_INTERNAL;
            mDisplayInfo.defaultModeId = MODE_ID;
            mDisplayInfo.defaultModeId = MODE_ID;
            mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
            mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
                    800, 600, /* refreshRate= */ 60)};
                    800, 600, /* refreshRate= */ 60)};
@@ -3856,6 +3912,7 @@ public class DisplayModeDirectorTest {
        @Override
        @Override
        public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
        public boolean getDisplayInfo(int displayId, DisplayInfo displayInfo) {
            displayInfo.copyFrom(mDisplayInfo);
            displayInfo.copyFrom(mDisplayInfo);
            displayInfo.displayId = displayId;
            return mDisplayInfoValid;
            return mDisplayInfoValid;
        }
        }


Loading