From 67aae3f3226e41eb495ed2f73082daaeffa00e7c Mon Sep 17 00:00:00 2001 From: Long Ling Date: Thu, 8 Aug 2019 16:05:44 -0700 Subject: [PATCH 1/2] 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 --- .../server/display/DisplayModeDirector.java | 308 ++++++++++++++---- 1 file changed, 243 insertions(+), 65 deletions(-) diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index c45a314e39ccb..5331aadec0932 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -38,13 +38,16 @@ import android.os.Message; import android.os.UserHandle; import android.os.PowerManager; import android.os.SystemClock; +import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.DisplayInfo; +import com.android.internal.os.BackgroundThread; import com.android.internal.R; import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory; import com.android.server.display.whitebalance.AmbientFilter; @@ -64,6 +67,8 @@ public class DisplayModeDirector { private static final boolean DEBUG = false; 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 // specific display. @@ -91,6 +96,7 @@ public class DisplayModeDirector { private final DisplayObserver mDisplayObserver; private final BrightnessObserver mBrightnessObserver; + private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; private Listener mListener; public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) { @@ -103,7 +109,7 @@ public class DisplayModeDirector { mSettingsObserver = new SettingsObserver(context, handler); mDisplayObserver = new DisplayObserver(context, handler); mBrightnessObserver = new BrightnessObserver(context, handler); - + mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings(); } /** @@ -405,7 +411,7 @@ public class DisplayModeDirector { void onAllowedDisplayModesChanged(); } - private static final class DisplayModeDirectorHandler extends Handler { + private final class DisplayModeDirectorHandler extends Handler { DisplayModeDirectorHandler(Looper looper) { super(looper, null, true /*async*/); } @@ -417,6 +423,23 @@ public class DisplayModeDirector { Listener listener = (Listener) msg.obj; listener.onAllowedDisplayModesChanged(); break; + + case MSG_BRIGHTNESS_THRESHOLDS_CHANGED: + Pair thresholds = (Pair) 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); private final Context mContext; - private final float mDefaultPeakRefreshRate; + private float mDefaultPeakRefreshRate; SettingsObserver(@NonNull Context context, @NonNull Handler handler) { super(handler); @@ -523,12 +546,33 @@ public class DisplayModeDirector { UserHandle.USER_SYSTEM); cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM); + + Float deviceConfigDefaultPeakRefresh = + mDeviceConfigDisplaySettings.getDefaultPeakRefreshRate(); + if (deviceConfigDefaultPeakRefresh != null) { + mDefaultPeakRefreshRate = deviceConfigDefaultPeakRefresh; + } + synchronized (mLock) { updateRefreshRateSettingLocked(); 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 public void onChange(boolean selfChange, Uri uri, int userId) { synchronized (mLock) { @@ -720,8 +764,8 @@ public class DisplayModeDirector { Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS); private final static int LIGHT_SENSOR_RATE_MS = 250; - private final int[] mDisplayBrightnessThresholds; - private final int[] mAmbientBrightnessThresholds; + private int[] mDisplayBrightnessThresholds; + private int[] mAmbientBrightnessThresholds; // valid threshold if any item from the array >= 0 private boolean mShouldObserveDisplayChange; private boolean mShouldObserveAmbientChange; @@ -734,10 +778,11 @@ public class DisplayModeDirector { private AmbientFilter mAmbientFilter; 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 - // off. After initialization, these states will be updated from the same handler thread. + // Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak + // 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 mPeakRefreshRateEnabled = false; private boolean mLowPowerModeEnabled = false; @@ -745,83 +790,63 @@ public class DisplayModeDirector { BrightnessObserver(Context context, Handler handler) { super(handler); mContext = context; + mScreenStateReceiver = new ScreenStateReceiver(mContext); mDisplayBrightnessThresholds = context.getResources().getIntArray( R.array.config_brightnessThresholdsOfPeakRefreshRate); mAmbientBrightnessThresholds = context.getResources().getIntArray( R.array.config_ambientThresholdsOfPeakRefreshRate); + if (mDisplayBrightnessThresholds.length != mAmbientBrightnessThresholds.length) { throw new RuntimeException("display brightness threshold array and ambient " + "brightness threshold array have different length"); } - - mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds); - mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds); } public void observe(SensorManager sensorManager) { - if (mShouldObserveDisplayChange) { - final ContentResolver cr = mContext.getContentResolver(); - cr.registerContentObserver(mDisplayBrightnessSetting, - false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM); - } - - if (mShouldObserveAmbientChange) { - Resources resources = mContext.getResources(); - String lightSensorType = resources.getString( - com.android.internal.R.string.config_displayLightSensorType); - - Sensor lightSensor = null; - if (!TextUtils.isEmpty(lightSensorType)) { - List sensors = sensorManager.getSensorList(Sensor.TYPE_ALL); - for (int i = 0; i < sensors.size(); i++) { - Sensor sensor = sensors.get(i); - if (lightSensorType.equals(sensor.getStringType())) { - lightSensor = sensor; - break; - } - } - } - - if (lightSensor == null) { - lightSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); - } - - if (lightSensor != null) { - final Resources res = mContext.getResources(); - - mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res); - mSensorManager = sensorManager; - mLightSensor = lightSensor; - - // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status. - if (mContext.getSystemService(PowerManager.class).isInteractive()) { - onScreenOn(true); - } - mScreenStateReceiver = new ScreenStateReceiver(mContext); - } - } - - if (mShouldObserveDisplayChange || mShouldObserveAmbientChange) { - synchronized (mLock) { - onBrightnessChangedLocked(); - } + 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 (mShouldObserveAmbientChange && mPeakRefreshRateEnabled != b) { + if (mPeakRefreshRateEnabled != b) { mPeakRefreshRateEnabled = b; updateSensorStatus(); } } public void onLowPowerModeEnabled(boolean b) { - if (mShouldObserveAmbientChange && mLowPowerModeEnabled != 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"); @@ -841,6 +866,67 @@ public class DisplayModeDirector { } } + private void restartObserver() { + mShouldObserveDisplayChange = checkShouldObserve(mDisplayBrightnessThresholds); + mShouldObserveAmbientChange = checkShouldObserve(mAmbientBrightnessThresholds); + + 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, + false /*notifyDescendants*/, this, UserHandle.USER_SYSTEM); + } else { + cr.unregisterContentObserver(this); + } + + if (mShouldObserveAmbientChange) { + Resources resources = mContext.getResources(); + String lightSensorType = resources.getString( + com.android.internal.R.string.config_displayLightSensorType); + + Sensor lightSensor = null; + if (!TextUtils.isEmpty(lightSensorType)) { + List sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL); + for (int i = 0; i < sensors.size(); i++) { + Sensor sensor = sensors.get(i); + if (lightSensorType.equals(sensor.getStringType())) { + lightSensor = sensor; + break; + } + } + } + + if (lightSensor == null) { + lightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + } + + if (lightSensor != null) { + final Resources res = mContext.getResources(); + + mAmbientFilter = DisplayWhiteBalanceFactory.createBrightnessFilter(res); + mLightSensor = lightSensor; + + // Intent.ACTION_SCREEN_ON is not sticky. Check current screen status. + if (mContext.getSystemService(PowerManager.class).isInteractive()) { + onScreenOn(true); + } + mScreenStateReceiver.register(); + } + } else { + mAmbientFilter = null; + mLightSensor = null; + mScreenStateReceiver.unregister(); + } + + updateSensorStatus(); + + synchronized (mLock) { + onBrightnessChangedLocked(); + } + } + /** * Checks to see if at least one value is positive, in which case it is necessary to listen * to value changes. @@ -904,7 +990,8 @@ public class DisplayModeDirector { return; } - if (mScreenOn && !mLowPowerModeEnabled && mPeakRefreshRateEnabled) { + if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled + && mPeakRefreshRateEnabled) { mSensorManager.registerListener(mLightSensorListener, mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler); } else { @@ -993,18 +1080,109 @@ public class DisplayModeDirector { }; private final class ScreenStateReceiver extends BroadcastReceiver { + final Context mContext; public ScreenStateReceiver(Context context) { - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(Intent.ACTION_SCREEN_ON); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - context.registerReceiver(this, filter, null, mHandler); + 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(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + 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 + public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) { + int[] brightnessThresholds = getBrightnessThresholds(); + int[] ambientThresholds = getAmbientThresholds(); + Float defaultPeakRefreshRate = getDefaultPeakRefreshRate(); + + mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED, + new Pair(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; + } + } + } From 6f13f122134f8c866a74c769ac0c6a86cc79acae Mon Sep 17 00:00:00 2001 From: Long Ling Date: Tue, 13 Aug 2019 16:07:14 -0700 Subject: [PATCH 2/2] DO NOT MERGE Move device config key high_refresh_rate_blacklist to display_manager high_refresh_rate_blacklist belongs to smooth display feature. Move the key from namespace window_manager to display_manager. Bug: 139138964 Test: atest WmTests:HighRefreshRateBlacklistTest Test: Manual adb shell device_config/dumpsys window Change-Id: I3ae8ecce80ef97c4683a1c18ad81dc78456e9d57 --- .../android/hardware/display/DisplayManager.java | 11 +++++++++++ core/java/android/provider/DeviceConfig.java | 9 --------- .../android/server/wm/HighRefreshRateBlacklist.java | 6 +++--- .../server/wm/HighRefreshRateBlacklistTest.java | 12 ++++++------ 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 21c49add6cba1..5d8fa92263c47 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -855,5 +855,16 @@ public final class DisplayManager { * @hide */ String KEY_PEAK_REFRESH_RATE_DEFAULT = "peak_refresh_rate_default"; + + /** + * Key for controlling which packages are explicitly blocked from running at refresh rates + * higher than 60hz. An app may be added to this list if they exhibit performance issues at + * higher refresh rates. + * + * @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER + * @see android.R.array#config_highRefreshRateBlacklist + * @hide + */ + String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist"; } } diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index c27576bacf967..c837b93461737 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -358,15 +358,6 @@ public final class DeviceConfig { */ String KEY_SYSTEM_GESTURE_EXCLUSION_LOG_DEBOUNCE_MILLIS = "system_gesture_exclusion_log_debounce_millis"; - - /** - * Key for controlling which packages are explicitly blocked from running at refresh rates - * higher than 60hz. - * - * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER - * @hide - */ - String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist"; } private static final Object sLock = new Object(); diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java index 5726cb2d87d4b..b33b68a7a5b2d 100644 --- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java +++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static android.provider.DeviceConfig.WindowManager.KEY_HIGH_REFRESH_RATE_BLACKLIST; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_HIGH_REFRESH_RATE_BLACKLIST; import android.annotation.NonNull; import android.annotation.Nullable; @@ -58,9 +58,9 @@ class HighRefreshRateBlacklist { @VisibleForTesting HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig) { mDefaultBlacklist = r.getStringArray(R.array.config_highRefreshRateBlacklist); - deviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + deviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, BackgroundThread.getExecutor(), new OnPropertyChangedListener()); - final String property = deviceConfig.getProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + final String property = deviceConfig.getProperty(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_HIGH_REFRESH_RATE_BLACKLIST); updateBlacklist(property); } diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java index e02b69c4b0589..cd90462fffe45 100644 --- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java @@ -16,7 +16,7 @@ package com.android.server.wm; -import static android.provider.DeviceConfig.WindowManager.KEY_HIGH_REFRESH_RATE_BLACKLIST; +import static android.hardware.display.DisplayManager.DeviceConfig.KEY_HIGH_REFRESH_RATE_BLACKLIST; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -126,9 +126,9 @@ public class HighRefreshRateBlacklistTest { @Override public String getProperty(String namespace, String name) { - if (!DeviceConfig.NAMESPACE_WINDOW_MANAGER.equals(namespace) + if (!DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace) || !KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)) { - throw new IllegalArgumentException("Only things in NAMESPACE_WINDOW_MANAGER " + throw new IllegalArgumentException("Only things in NAMESPACE_DISPLAY_MANAGER " + "supported."); } return mBlacklist; @@ -138,8 +138,8 @@ public class HighRefreshRateBlacklistTest { public void addOnPropertyChangedListener(String namespace, Executor executor, DeviceConfig.OnPropertyChangedListener listener) { - if (!DeviceConfig.NAMESPACE_WINDOW_MANAGER.equals(namespace)) { - throw new IllegalArgumentException("Only things in NAMESPACE_WINDOW_MANAGER " + if (!DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace)) { + throw new IllegalArgumentException("Only things in NAMESPACE_DISPLAY_MANAGER " + "supported."); } mListeners.add(new Pair<>(listener, executor)); @@ -153,7 +153,7 @@ public class HighRefreshRateBlacklistTest { final Executor executor = listenerInfo.second; final DeviceConfig.OnPropertyChangedListener listener = listenerInfo.first; executor.execute(() -> { - listener.onPropertyChanged(DeviceConfig.NAMESPACE_WINDOW_MANAGER, + listener.onPropertyChanged(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_HIGH_REFRESH_RATE_BLACKLIST, blacklist); latch.countDown(); });