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

Commit 67aae3f3 authored by Long Ling's avatar Long Ling
Browse files

DO NOT MERGE Allow DeviceConfig to change display settings

Allow DeviceConfig to change default refresh rate and 60 hz only
thresholds.

Bug: 139138964
Change-Id: I3bf5f8cf7a99e4723265138004fbbd08102119d9
parent 66e9298a
Loading
Loading
Loading
Loading
+232 −54
Original line number Original line Diff line number Diff line
@@ -38,13 +38,16 @@ import android.os.Message;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.PowerManager;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.Display;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.DisplayInfo;


import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
import com.android.internal.R;
import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
import com.android.server.display.whitebalance.AmbientFilter;
import com.android.server.display.whitebalance.AmbientFilter;
@@ -64,6 +67,8 @@ public class DisplayModeDirector {
    private static final boolean DEBUG = false;
    private static final boolean DEBUG = false;


    private static final int MSG_ALLOWED_MODES_CHANGED = 1;
    private static final int MSG_ALLOWED_MODES_CHANGED = 1;
    private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
    private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;


    // Special ID used to indicate that given vote is to be applied globally, rather than to a
    // Special ID used to indicate that given vote is to be applied globally, rather than to a
    // specific display.
    // specific display.
@@ -91,6 +96,7 @@ public class DisplayModeDirector {
    private final DisplayObserver mDisplayObserver;
    private final DisplayObserver mDisplayObserver;
    private final BrightnessObserver mBrightnessObserver;
    private final BrightnessObserver mBrightnessObserver;


    private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
    private Listener mListener;
    private Listener mListener;


    public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
    public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
@@ -103,7 +109,7 @@ public class DisplayModeDirector {
        mSettingsObserver = new SettingsObserver(context, handler);
        mSettingsObserver = new SettingsObserver(context, handler);
        mDisplayObserver = new DisplayObserver(context, handler);
        mDisplayObserver = new DisplayObserver(context, handler);
        mBrightnessObserver = new BrightnessObserver(context, handler);
        mBrightnessObserver = new BrightnessObserver(context, handler);

        mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
    }
    }


    /**
    /**
@@ -405,7 +411,7 @@ public class DisplayModeDirector {
        void onAllowedDisplayModesChanged();
        void onAllowedDisplayModesChanged();
    }
    }


    private static final class DisplayModeDirectorHandler extends Handler {
    private final class DisplayModeDirectorHandler extends Handler {
        DisplayModeDirectorHandler(Looper looper) {
        DisplayModeDirectorHandler(Looper looper) {
            super(looper, null, true /*async*/);
            super(looper, null, true /*async*/);
        }
        }
@@ -417,6 +423,23 @@ public class DisplayModeDirector {
                    Listener listener = (Listener) msg.obj;
                    Listener listener = (Listener) msg.obj;
                    listener.onAllowedDisplayModesChanged();
                    listener.onAllowedDisplayModesChanged();
                    break;
                    break;

                case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
                    Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;

                    if (thresholds != null) {
                        mBrightnessObserver.onDeviceConfigThresholdsChanged(
                                thresholds.first, thresholds.second);
                    } else {
                        mBrightnessObserver.onDeviceConfigThresholdsChanged(null, null);
                    }
                    break;

                case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED:
                    Float defaultPeakRefreshRate = (Float) msg.obj;
                    mSettingsObserver.onDeviceConfigDefaultPeakRefreshRateChanged(
                            defaultPeakRefreshRate);
                    break;
            }
            }
        }
        }
    }
    }
@@ -508,7 +531,7 @@ public class DisplayModeDirector {
                Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);
                Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE);


        private final Context mContext;
        private final Context mContext;
        private final float mDefaultPeakRefreshRate;
        private float mDefaultPeakRefreshRate;


        SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
        SettingsObserver(@NonNull Context context, @NonNull Handler handler) {
            super(handler);
            super(handler);
@@ -523,12 +546,33 @@ public class DisplayModeDirector {
                    UserHandle.USER_SYSTEM);
                    UserHandle.USER_SYSTEM);
            cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
            cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
                    UserHandle.USER_SYSTEM);
                    UserHandle.USER_SYSTEM);

            Float deviceConfigDefaultPeakRefresh =
                    mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate();
            if (deviceConfigDefaultPeakRefresh != null) {
                mDefaultPeakRefreshRate = deviceConfigDefaultPeakRefresh;
            }

            synchronized (mLock) {
            synchronized (mLock) {
                updateRefreshRateSettingLocked();
                updateRefreshRateSettingLocked();
                updateLowPowerModeSettingLocked();
                updateLowPowerModeSettingLocked();
            }
            }
        }
        }


        public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
            if (defaultPeakRefreshRate == null) {
                defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
                        R.integer.config_defaultPeakRefreshRate);
            }

            if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
                synchronized (mLock) {
                    mDefaultPeakRefreshRate = defaultPeakRefreshRate;
                    updateRefreshRateSettingLocked();
                }
            }
        }

        @Override
        @Override
        public void onChange(boolean selfChange, Uri uri, int userId) {
        public void onChange(boolean selfChange, Uri uri, int userId) {
            synchronized (mLock) {
            synchronized (mLock) {
@@ -720,8 +764,8 @@ public class DisplayModeDirector {
                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);


        private final static int LIGHT_SENSOR_RATE_MS = 250;
        private final static int LIGHT_SENSOR_RATE_MS = 250;
        private final int[] mDisplayBrightnessThresholds;
        private int[] mDisplayBrightnessThresholds;
        private final int[] mAmbientBrightnessThresholds;
        private int[] mAmbientBrightnessThresholds;
        // valid threshold if any item from the array >= 0
        // valid threshold if any item from the array >= 0
        private boolean mShouldObserveDisplayChange;
        private boolean mShouldObserveDisplayChange;
        private boolean mShouldObserveAmbientChange;
        private boolean mShouldObserveAmbientChange;
@@ -734,10 +778,11 @@ public class DisplayModeDirector {
        private AmbientFilter mAmbientFilter;
        private AmbientFilter mAmbientFilter;


        private final Context mContext;
        private final Context mContext;
        private ScreenStateReceiver mScreenStateReceiver;
        private final ScreenStateReceiver mScreenStateReceiver;


        // Enable light sensor only when screen is on, peak refresh rate enabled and low power mode
        // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
        // off. After initialization, these states will be updated from the same handler thread.
        // refresh rate enabled and low power mode off. After initialization, these states will
        // be updated from the same handler thread.
        private boolean mScreenOn = false;
        private boolean mScreenOn = false;
        private boolean mPeakRefreshRateEnabled = false;
        private boolean mPeakRefreshRateEnabled = false;
        private boolean mLowPowerModeEnabled = false;
        private boolean mLowPowerModeEnabled = false;
@@ -745,24 +790,95 @@ public class DisplayModeDirector {
        BrightnessObserver(Context context, Handler handler) {
        BrightnessObserver(Context context, Handler handler) {
            super(handler);
            super(handler);
            mContext = context;
            mContext = context;
            mScreenStateReceiver = new ScreenStateReceiver(mContext);
            mDisplayBrightnessThresholds = context.getResources().getIntArray(
            mDisplayBrightnessThresholds = context.getResources().getIntArray(
                    R.array.config_brightnessThresholdsOfPeakRefreshRate);
                    R.array.config_brightnessThresholdsOfPeakRefreshRate);
            mAmbientBrightnessThresholds = context.getResources().getIntArray(
            mAmbientBrightnessThresholds = context.getResources().getIntArray(
                    R.array.config_ambientThresholdsOfPeakRefreshRate);
                    R.array.config_ambientThresholdsOfPeakRefreshRate);

            if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
            if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) {
                throw new RuntimeException("display brightness threshold array and ambient "
                throw new RuntimeException("display brightness threshold array and ambient "
                        + "brightness threshold array have different length");
                        + "brightness threshold array have different length");
            }
            }
        }

        public void observe(SensorManager sensorManager) {
            mSensorManager = sensorManager;
            // DeviceConfig is accessible after system ready.
            int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
            int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();

            if (brightnessThresholds != null && ambientThresholds != null
                    && brightnessThresholds.length == ambientThresholds.length) {
                mDisplayBrightnessThresholds = brightnessThresholds;
                mAmbientBrightnessThresholds = ambientThresholds;
            }
            restartObserver();
            mDeviceConfigDisplaySettings.startListening();
        }

        public void onPeakRefreshRateEnabled(boolean b) {
            if (mPeakRefreshRateEnabled != b) {
                mPeakRefreshRateEnabled = b;
                updateSensorStatus();
            }
        }

        public void onLowPowerModeEnabled(boolean b) {
            if (mLowPowerModeEnabled != b) {
                mLowPowerModeEnabled = b;
                updateSensorStatus();
            }
        }

        public void onDeviceConfigThresholdsChanged(int[] brightnessThresholds,
                int[] ambientThresholds) {
            if (brightnessThresholds != null && ambientThresholds != null
                    && brightnessThresholds.length == ambientThresholds.length) {
                mDisplayBrightnessThresholds = brightnessThresholds;
                mAmbientBrightnessThresholds = ambientThresholds;
            } else {
                // Invalid or empty. Use device default.
                mDisplayBrightnessThresholds = mContext.getResources().getIntArray(
                        R.array.config_brightnessThresholdsOfPeakRefreshRate);
                mAmbientBrightnessThresholds = mContext.getResources().getIntArray(
                        R.array.config_ambientThresholdsOfPeakRefreshRate);
            }
            restartObserver();
        }

        public void dumpLocked(PrintWriter pw) {
            pw.println("  BrightnessObserver");

            for (int d: mDisplayBrightnessThresholds) {
                pw.println("    mDisplayBrightnessThreshold: " + d);
            }

            for (int d: mAmbientBrightnessThresholds) {
                pw.println("    mAmbientBrightnessThreshold: " + d);
            }
        }

        @Override
        public void onChange(boolean selfChange, Uri uri, int userId) {
            synchronized (mLock) {
                onBrightnessChangedLocked();
            }
        }


        private void restartObserver() {
            mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
            mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds);
            mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
            mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds);
        }


        public void observe(SensorManager sensorManager) {
            if (mShouldObserveDisplayChange) {
            final ContentResolver cr = mContext.getContentResolver();
            final ContentResolver cr = mContext.getContentResolver();
            if (mShouldObserveDisplayChange) {
                // Content Service does not check if an listener has already been registered.
                // To ensure only one listener is registered, force an unregistration first.
                cr.unregisterContentObserver(this);
                cr.registerContentObserver(mDisplayBrightnessSetting,
                cr.registerContentObserver(mDisplayBrightnessSetting,
                        false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
                        false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM);
            } else {
                cr.unregisterContentObserver(this);
            }
            }


            if (mShouldObserveAmbientChange) {
            if (mShouldObserveAmbientChange) {
@@ -772,7 +888,7 @@ public class DisplayModeDirector {


                Sensor lightSensor = null;
                Sensor lightSensor = null;
                if (!TextUtils.isEmpty(lightSensorType)) {
                if (!TextUtils.isEmpty(lightSensorType)) {
                    List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
                    List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
                    for (int i = 0; i < sensors.size(); i++) {
                    for (int i = 0; i < sensors.size(); i++) {
                        Sensor sensor = sensors.get(i);
                        Sensor sensor = sensors.get(i);
                        if (lightSensorType.equals(sensor.getStringType())) {
                        if (lightSensorType.equals(sensor.getStringType())) {
@@ -783,59 +899,29 @@ public class DisplayModeDirector {
                }
                }


                if (lightSensor == null) {
                if (lightSensor == null) {
                    lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
                    lightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
                }
                }


                if (lightSensor != null) {
                if (lightSensor != null) {
                    final Resources res = mContext.getResources();
                    final Resources res = mContext.getResources();


                    mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res);
                    mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res);
                    mSensorManager = sensorManager;
                    mLightSensor = lightSensor;
                    mLightSensor = lightSensor;


                    // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
                    // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status.
                    if (mContext.getSystemService(PowerManager.class).isInteractive()) {
                    if (mContext.getSystemService(PowerManager.class).isInteractive()) {
                        onScreenOn(true);
                        onScreenOn(true);
                    }
                    }
                    mScreenStateReceiver = new ScreenStateReceiver(mContext);
                    mScreenStateReceiver.register();
                }
            }

            if (mShouldObserveDisplayChange || mShouldObserveAmbientChange) {
                synchronized (mLock) {
                    onBrightnessChangedLocked();
                }
                }
                }
            } else {
                mAmbientFilter = null;
                mLightSensor = null;
                mScreenStateReceiver.unregister();
            }
            }


        public void onPeakRefreshRateEnabled(boolean b) {
            if (mShouldObserveAmbientChange && mPeakRefreshRateEnabled != b) {
                mPeakRefreshRateEnabled = b;
            updateSensorStatus();
            updateSensorStatus();
            }
        }

        public void onLowPowerModeEnabled(boolean b) {
            if (mShouldObserveAmbientChange && mLowPowerModeEnabled != b) {
                mLowPowerModeEnabled = b;
                updateSensorStatus();
            }
        }

        public void dumpLocked(PrintWriter pw) {
            pw.println("  BrightnessObserver");

            for (int d: mDisplayBrightnessThresholds) {
                pw.println("    mDisplayBrightnessThreshold: " + d);
            }

            for (int d: mAmbientBrightnessThresholds) {
                pw.println("    mAmbientBrightnessThreshold: " + d);
            }
        }


        @Override
        public void onChange(boolean selfChange, Uri uri, int userId) {
            synchronized (mLock) {
            synchronized (mLock) {
                onBrightnessChangedLocked();
                onBrightnessChangedLocked();
            }
            }
@@ -904,7 +990,8 @@ public class DisplayModeDirector {
                return;
                return;
            }
            }


            if (mScreenOn && !mLowPowerModeEnabled && mPeakRefreshRateEnabled) {
            if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled
                    && mPeakRefreshRateEnabled) {
                mSensorManager.registerListener(mLightSensorListener,
                mSensorManager.registerListener(mLightSensorListener,
                        mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
                        mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
            } else {
            } else {
@@ -993,18 +1080,109 @@ public class DisplayModeDirector {
        };
        };


        private final class ScreenStateReceiver extends BroadcastReceiver {
        private final class ScreenStateReceiver extends BroadcastReceiver {
            final Context mContext;
            public ScreenStateReceiver(Context context) {
            public ScreenStateReceiver(Context context) {
                mContext = context;
            }

            @Override
            public void onReceive(Context context, Intent intent) {
                onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
            }

            public void register() {
                IntentFilter filter = new IntentFilter();
                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_SCREEN_OFF);
                filter.addAction(Intent.ACTION_SCREEN_OFF);
                filter.addAction(Intent.ACTION_SCREEN_ON);
                filter.addAction(Intent.ACTION_SCREEN_ON);
                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
                context.registerReceiver(this, filter, null, mHandler);
                mContext.registerReceiver(this, filter, null, mHandler);
            }

            public void unregister() {
                mContext.unregisterReceiver(this);
            }
        }
    }

    private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {

        public DeviceConfigDisplaySettings() {
        }

        public void startListening() {
            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                    BackgroundThread.getExecutor(), this);
        }

        /*
         * Return null if no such property or wrong format (not comma separated integers).
         */
        public int[] getBrightnessThresholds() {
            return getIntArrayProperty(
                    DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_BRIGHTNESS_THRESHOLDS);
        }

        /*
         * Return null if no such property or wrong format (not comma separated integers).
         */
        public int[] getAmbientThresholds() {
            return getIntArrayProperty(
                    DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_AMBIENT_THRESHOLDS);
        }

        /*
         * Return null if no such property
         */
        public Float getDefaultPeakRefreshRate() {
            float defaultPeakRefreshRate = DeviceConfig.getFloat(
                    DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
                    DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1);

            if (defaultPeakRefreshRate == -1) {
                return null;
            }
            return defaultPeakRefreshRate;
        }
        }


        @Override
        @Override
            public void onReceive(Context context, Intent intent) {
        public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
                onScreenOn(Intent.ACTION_SCREEN_ON.equals(intent.getAction()));
            int[] brightnessThresholds = getBrightnessThresholds();
            int[] ambientThresholds = getAmbientThresholds();
            Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();

            mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
                    new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
                    .sendToTarget();
            mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
                    defaultPeakRefreshRate).sendToTarget();
        }

        private int[] getIntArrayProperty(String prop) {
            String strArray = DeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
                    null);

            if (strArray != null) {
                return parseIntArray(strArray);
            }
            }

            return null;
        }

        private int[] parseIntArray(@NonNull String strArray) {
            String[] items = strArray.split(",");
            int[] array = new int[items.length];

            try {
                for (int i = 0; i < array.length; i++) {
                    array[i] = Integer.parseInt(items[i]);
                }
                }
            } catch (NumberFormatException e) {
                Slog.e(TAG, "Incorrect format for array: '" + strArray + "'", e);
                array = null;
            }
            }

            return array;
        }
    }

}
}