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

Commit 46fff422 authored by Daniel Solomon's avatar Daniel Solomon Committed by Yichi Chen
Browse files

Separate refresh rate restrictions for different High Brightness Modes

Allow setting a different refresh rate for High Brightness Mode for HDR
and for Sunlight.

Bug: 196691596
Test: atest DisplayModeDirectorTest
Test: Manual:
      1. Ensure HBM for HDR takes presedence over HBM for Sunlight
      2. Ensure app refresh rate votes override bothHBM for Sunlight
Change-Id: I4a29c47f218046d0852178ad5dc7484a86ef8607
Merged-In: I4a29c47f218046d0852178ad5dc7484a86ef8607
parent 7e783bb0
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -1257,6 +1257,23 @@ public final class DisplayManager {
         */
        String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
                "fixed_refresh_rate_high_ambient_brightness_thresholds";

        /**
         * Key for refresh rate when the device is in high brightness mode for sunlight visility.
         *
         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
         * @see android.R.integer#config_defaultRefreshRateInHbmSunlight
         */
        String KEY_REFRESH_RATE_IN_HBM_SUNLIGHT = "refresh_rate_in_hbm_sunlight";

        /**
         * Key for refresh rate when the device is in high brightness mode for HDR.
         *
         * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
         * @see android.R.integer#config_defaultRefreshRateInHbmHdr
         */
        String KEY_REFRESH_RATE_IN_HBM_HDR = "refresh_rate_in_hbm_hdr";

        /**
         * Key for default peak refresh rate
         *
+7 −0
Original line number Diff line number Diff line
@@ -4492,6 +4492,13 @@
         If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
    <integer name="config_fixedRefreshRateInHighZone">0</integer>

    <!-- Default refresh rate while the device has high brightness mode enabled for Sunlight.
         This value overrides values from DisplayDeviceConfig -->
    <integer name="config_defaultRefreshRateInHbmSunlight">0</integer>

    <!-- Default refresh rate while the device has high brightness mode enabled for HDR. -->
    <integer name="config_defaultRefreshRateInHbmHdr">0</integer>

    <!-- The type of the light sensor to be used by the display framework for things like
         auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
    <string name="config_displayLightSensorType" translatable="false" />
+2 −0
Original line number Diff line number Diff line
@@ -3948,6 +3948,8 @@
  <java-symbol type="integer" name="config_defaultRefreshRateInZone" />
  <java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
  <java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
  <java-symbol type="integer" name="config_defaultRefreshRateInHbmSunlight" />
  <java-symbol type="integer" name="config_defaultRefreshRateInHbmHdr" />

  <!-- For fixed refresh rate displays in high brightness-->
  <java-symbol type="integer" name="config_fixedRefreshRateInHighZone" />
+151 −28
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.DisplayInfo;

@@ -77,7 +78,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;


/**
 * The DisplayModeDirector is responsible for determining what modes are allowed to be automatically
 * picked by the system based on system-wide and display-specific configuration.
@@ -92,6 +92,8 @@ public class DisplayModeDirector {
    private static final int MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED = 4;
    private static final int MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED = 5;
    private static final int MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED = 6;
    private static final int MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED = 7;
    private static final int MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED = 8;

    // Special ID used to indicate that given vote is to be applied globally, rather than to a
    // specific display.
@@ -161,9 +163,10 @@ public class DisplayModeDirector {
            }
        };
        mSensorObserver = new SensorObserver(context, ballotBox, injector);
        mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
        mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
        mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(),
                mDeviceConfigDisplaySettings);
        mDeviceConfig = injector.getDeviceConfig();
        mAlwaysRespectAppRequest = false;
    }
@@ -723,6 +726,11 @@ public class DisplayModeDirector {
        return mUdfpsObserver;
    }

    @VisibleForTesting
    HbmObserver getHbmObserver() {
        return mHbmObserver;
    }

    @VisibleForTesting
    DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
            float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
@@ -792,6 +800,19 @@ public class DisplayModeDirector {
                            (DesiredDisplayModeSpecsListener) msg.obj;
                    desiredDisplayModeSpecsListener.onDesiredDisplayModeSpecsChanged();
                    break;

                case MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED: {
                    int refreshRateInHbmSunlight = msg.arg1;
                    mHbmObserver.onDeviceConfigRefreshRateInHbmSunlightChanged(
                            refreshRateInHbmSunlight);
                    break;
                }

                case MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED: {
                    int refreshRateInHbmHdr = msg.arg1;
                    mHbmObserver.onDeviceConfigRefreshRateInHbmHdrChanged(refreshRateInHbmHdr);
                    break;
                }
            }
        }
    }
@@ -918,16 +939,19 @@ public class DisplayModeDirector {
        // result is a range.
        public static final int PRIORITY_FLICKER_REFRESH_RATE = 1;

        // High-brightness-mode may need a specific range of refresh-rates to function properly.
        public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 2;

        // SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
        // It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
        public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 2;
        public static final int PRIORITY_USER_SETTING_MIN_REFRESH_RATE = 3;

        // APP_REQUEST_REFRESH_RATE_RANGE is used to for internal apps to limit the refresh
        // rate in certain cases, mostly to preserve power.
        // @see android.view.WindowManager.LayoutParams#preferredMinRefreshRate
        // @see android.view.WindowManager.LayoutParams#preferredMaxRefreshRate
        // It votes to [preferredMinRefreshRate, preferredMaxRefreshRate].
        public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 3;
        public static final int PRIORITY_APP_REQUEST_REFRESH_RATE_RANGE = 4;

        // We split the app request into different priorities in case we can satisfy one desire
        // without the other.
@@ -942,27 +966,24 @@ public class DisplayModeDirector {
        // The preferred refresh rate is set on the main surface of the app outside of
        // DisplayModeDirector.
        // @see com.android.server.wm.WindowState#updateFrameRateSelectionPriorityIfNeeded
        public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 4;
        public static final int PRIORITY_APP_REQUEST_SIZE = 5;
        public static final int PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE = 5;
        public static final int PRIORITY_APP_REQUEST_SIZE = 6;

        // SETTING_PEAK_REFRESH_RATE has a high priority and will restrict the bounds of the rest
        // of low priority voters. It votes [0, max(PEAK, MIN)]
        public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 6;
        public static final int PRIORITY_USER_SETTING_PEAK_REFRESH_RATE = 7;

        // LOW_POWER_MODE force display to [0, 60HZ] if Settings.Global.LOW_POWER_MODE is on.
        public static final int PRIORITY_LOW_POWER_MODE = 7;
        public static final int PRIORITY_LOW_POWER_MODE = 8;

        // PRIORITY_FLICKER_REFRESH_RATE_SWITCH votes for disabling refresh rate switching. If the
        // higher priority voters' result is a range, it will fix the rate to a single choice.
        // It's used to avoid refresh rate switches in certain conditions which may result in the
        // user seeing the display flickering when the switches occur.
        public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
        public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 9;

        // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
        public static final int PRIORITY_SKIN_TEMPERATURE = 9;

        // High-brightness-mode may need a specific range of refresh-rates to function properly.
        public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10;
        public static final int PRIORITY_SKIN_TEMPERATURE = 10;

        // The proximity sensor needs the refresh rate to be locked in order to function, so this is
        // set to a high priority.
@@ -2258,33 +2279,78 @@ public class DisplayModeDirector {
     * HBM that are associated with that display. Restrictions are retrieved from
     * DisplayManagerInternal but originate in the display-device-config file.
     */
    private static class HbmObserver implements DisplayManager.DisplayListener {
    public static class HbmObserver implements DisplayManager.DisplayListener {
        private final BallotBox mBallotBox;
        private final Handler mHandler;
        private final SparseBooleanArray mHbmEnabled = new SparseBooleanArray();
        private final SparseIntArray mHbmMode = new SparseIntArray();
        private final Injector mInjector;
        private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
        private int mRefreshRateInHbmSunlight;
        private int mRefreshRateInHbmHdr;

        private DisplayManagerInternal mDisplayManagerInternal;

        HbmObserver(Injector injector, BallotBox ballotBox, Handler handler) {
        HbmObserver(Injector injector, BallotBox ballotBox, Handler handler,
                DeviceConfigDisplaySettings displaySettings) {
            mInjector = injector;
            mBallotBox = ballotBox;
            mHandler = handler;
            mDeviceConfigDisplaySettings = displaySettings;
        }

        public void observe() {
            mRefreshRateInHbmSunlight = mDeviceConfigDisplaySettings.getRefreshRateInHbmSunlight();
            mRefreshRateInHbmHdr = mDeviceConfigDisplaySettings.getRefreshRateInHbmHdr();

            mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
            mInjector.registerDisplayListener(this, mHandler,
                    DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS
                    | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
        }

        /**
         * @return the refresh to lock to when the device is in high brightness mode for Sunlight.
         */
        @VisibleForTesting
        int getRefreshRateInHbmSunlight() {
            return mRefreshRateInHbmSunlight;
        }

        /**
         * @return the refresh to lock to when the device is in high brightness mode for HDR.
         */
        @VisibleForTesting
        int getRefreshRateInHbmHdr() {
            return mRefreshRateInHbmHdr;
        }

        /**
         * Recalculates the HBM vote when the device config has been changed.
         */
        public void onDeviceConfigRefreshRateInHbmSunlightChanged(int refreshRate) {
            if (refreshRate != mRefreshRateInHbmSunlight) {
                mRefreshRateInHbmSunlight = refreshRate;
                onDeviceConfigRefreshRateInHbmChanged();
            }
        }

        /**
         * Recalculates the HBM vote when the device config has been changed.
         */
        public void onDeviceConfigRefreshRateInHbmHdrChanged(int refreshRate) {
            if (refreshRate != mRefreshRateInHbmHdr) {
                mRefreshRateInHbmHdr = refreshRate;
                onDeviceConfigRefreshRateInHbmChanged();
            }
        }

        @Override
        public void onDisplayAdded(int displayId) {}

        @Override
        public void onDisplayRemoved(int displayId) {
            mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, null);
            mHbmMode.delete(displayId);
        }

        @Override
@@ -2294,15 +2360,33 @@ public class DisplayModeDirector {
                // Display no longer there. Assume we'll get an onDisplayRemoved very soon.
                return;
            }
            final boolean isHbmEnabled =
                    info.highBrightnessMode != BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
            if (isHbmEnabled == mHbmEnabled.get(displayId)) {
            final int hbmMode = info.highBrightnessMode;
            if (hbmMode == mHbmMode.get(displayId)) {
                // no change, ignore.
                return;
            }
            mHbmMode.put(displayId, hbmMode);
            recalculateVotesForDisplay(displayId);
        }

        private void onDeviceConfigRefreshRateInHbmChanged() {
            final int[] displayIds = mHbmMode.copyKeys();
            if (displayIds != null) {
                for (int id : displayIds) {
                    recalculateVotesForDisplay(id);
                }
            }
        }

        private void recalculateVotesForDisplay(int displayId) {
            final int hbmMode = mHbmMode.get(displayId, BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
            Vote vote = null;
            mHbmEnabled.put(displayId, isHbmEnabled);
            if (isHbmEnabled) {
            if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
                // Device resource properties take priority over DisplayDeviceConfig
                if (mRefreshRateInHbmSunlight > 0) {
                    vote = Vote.forRefreshRates(mRefreshRateInHbmSunlight,
                            mRefreshRateInHbmSunlight);
                } else {
                    final List<RefreshRateLimitation> limits =
                        mDisplayManagerInternal.getRefreshRateLimitations(displayId);
                    for (int i = 0; limits != null && i < limits.size(); i++) {
@@ -2313,12 +2397,19 @@ public class DisplayModeDirector {
                        }
                    }
                }
            }
            if (hbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
                    && mRefreshRateInHbmHdr > 0) {
                vote = Vote.forRefreshRates(mRefreshRateInHbmHdr, mRefreshRateInHbmHdr);
            }
            mBallotBox.vote(displayId, Vote.PRIORITY_HIGH_BRIGHTNESS_MODE, vote);
        }

        void dumpLocked(PrintWriter pw) {
            pw.println("   HbmObserver");
            pw.println("     mHbmEnabled: " + mHbmEnabled);
            pw.println("     mHbmMode: " + mHbmMode);
            pw.println("     mRefreshRateInHbmSunlight: " + mRefreshRateInHbmSunlight);
            pw.println("     mRefreshRateInHbmHdr: " + mRefreshRateInHbmHdr);
        }
    }

@@ -2437,6 +2528,29 @@ public class DisplayModeDirector {
            return refreshRate;
        }

        public int getRefreshRateInHbmSunlight() {
            final int defaultRefreshRateInHbmSunlight =
                    mContext.getResources().getInteger(
                            R.integer.config_defaultRefreshRateInHbmSunlight);

            final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                    DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_SUNLIGHT,
                    defaultRefreshRateInHbmSunlight);

            return refreshRate;
        }

        public int getRefreshRateInHbmHdr() {
            final int defaultRefreshRateInHbmHdr =
                    mContext.getResources().getInteger(R.integer.config_defaultRefreshRateInHbmHdr);

            final int refreshRate = mDeviceConfig.getInt(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                    DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HBM_HDR,
                    defaultRefreshRateInHbmHdr);

            return refreshRate;
        }

        /*
         * Return null if no such property
         */
@@ -2476,6 +2590,15 @@ public class DisplayModeDirector {
                    .sendToTarget();
            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0)
                    .sendToTarget();

            final int refreshRateInHbmSunlight = getRefreshRateInHbmSunlight();
            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_SUNLIGHT_CHANGED,
                    refreshRateInHbmSunlight, 0)
                    .sendToTarget();

            final int refreshRateInHbmHdr = getRefreshRateInHbmHdr();
            mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HBM_HDR_CHANGED, refreshRateInHbmHdr, 0)
                    .sendToTarget();
        }

        private int[] getIntArrayProperty(String prop) {
+149 −3

File changed.

Preview size limit exceeded, changes collapsed.