Merge changes from topic "r3_flicker_high_brightness" into rvc-qpr-dev
* changes: Allow DeviceConfig to change display settings for high zone Set fixed fps when ambient or display brightness is high Add FakeSettingsProviderRule class
This commit is contained in:
committed by
Android (Google) Code Review
commit
11bee77de6
@@ -875,12 +875,52 @@ public final class DisplayManager {
|
||||
public interface DeviceConfig {
|
||||
|
||||
/**
|
||||
* Key for refresh rate in the zone defined by thresholds.
|
||||
* Key for refresh rate in the low zone defined by thresholds.
|
||||
*
|
||||
* Note that the name and value don't match because they were added before we had a high
|
||||
* zone to consider.
|
||||
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||
* @see android.R.integer#config_defaultZoneBehavior
|
||||
*/
|
||||
String KEY_REFRESH_RATE_IN_ZONE = "refresh_rate_in_zone";
|
||||
String KEY_REFRESH_RATE_IN_LOW_ZONE = "refresh_rate_in_zone";
|
||||
|
||||
/**
|
||||
* Key for accessing the low display brightness thresholds for the configured refresh
|
||||
* rate zone.
|
||||
* The value will be a pair of comma separated integers representing the minimum and maximum
|
||||
* thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
|
||||
*
|
||||
* Note that the name and value don't match because they were added before we had a high
|
||||
* zone to consider.
|
||||
*
|
||||
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||
* @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
|
||||
* @hide
|
||||
*/
|
||||
String KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS =
|
||||
"peak_refresh_rate_brightness_thresholds";
|
||||
|
||||
/**
|
||||
* Key for accessing the low ambient brightness thresholds for the configured refresh
|
||||
* rate zone. The value will be a pair of comma separated integers representing the minimum
|
||||
* and maximum thresholds of the zone, respectively, in lux.
|
||||
*
|
||||
* Note that the name and value don't match because they were added before we had a high
|
||||
* zone to consider.
|
||||
*
|
||||
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||
* @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
|
||||
* @hide
|
||||
*/
|
||||
String KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS =
|
||||
"peak_refresh_rate_ambient_thresholds";
|
||||
/**
|
||||
* Key for refresh rate in the high zone defined by thresholds.
|
||||
*
|
||||
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||
* @see android.R.integer#config_fixedRefreshRateInHighZone
|
||||
*/
|
||||
String KEY_REFRESH_RATE_IN_HIGH_ZONE = "refresh_rate_in_high_zone";
|
||||
|
||||
/**
|
||||
* Key for accessing the display brightness thresholds for the configured refresh rate zone.
|
||||
@@ -888,11 +928,11 @@ public final class DisplayManager {
|
||||
* thresholds of the zone, respectively, in display backlight units (i.e. [0, 255]).
|
||||
*
|
||||
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||
* @see android.R.array#config_brightnessThresholdsOfPeakRefreshRate
|
||||
* @see android.R.array#config_brightnessHighThresholdsOfFixedRefreshRate
|
||||
* @hide
|
||||
*/
|
||||
String KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS =
|
||||
"peak_refresh_rate_brightness_thresholds";
|
||||
String KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS =
|
||||
"fixed_refresh_rate_high_display_brightness_thresholds";
|
||||
|
||||
/**
|
||||
* Key for accessing the ambient brightness thresholds for the configured refresh rate zone.
|
||||
@@ -900,12 +940,11 @@ public final class DisplayManager {
|
||||
* thresholds of the zone, respectively, in lux.
|
||||
*
|
||||
* @see android.provider.DeviceConfig#NAMESPACE_DISPLAY_MANAGER
|
||||
* @see android.R.array#config_ambientThresholdsOfPeakRefreshRate
|
||||
* @see android.R.array#config_ambientHighThresholdsOfFixedRefreshRate
|
||||
* @hide
|
||||
*/
|
||||
String KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS =
|
||||
"peak_refresh_rate_ambient_thresholds";
|
||||
|
||||
String KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS =
|
||||
"fixed_refresh_rate_high_ambient_brightness_thresholds";
|
||||
/**
|
||||
* Key for default peak refresh rate
|
||||
*
|
||||
|
||||
@@ -4138,6 +4138,35 @@
|
||||
If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
|
||||
<integer name="config_defaultRefreshRateInZone">0</integer>
|
||||
|
||||
<!-- The display uses different gamma curves for different refresh rates. It's hard for panel
|
||||
vendor to tune the curves to have exact same brightness for different refresh rate. So
|
||||
flicker could be observed at switch time. The issue can be observed on the screen with
|
||||
even full white content at the high brightness. To prevent flickering, we support fixed
|
||||
refresh rates if the display and ambient brightness are equal to or above the provided
|
||||
thresholds. You can define multiple threshold levels as higher brightness environments
|
||||
may have lower display brightness requirements for the flickering is visible. And the
|
||||
high brightness environment could have higher threshold.
|
||||
For example, fixed refresh rate if
|
||||
display brightness >= disp0 && ambient brightness >= amb0
|
||||
|| display brightness >= disp1 && ambient brightness >= amb1 -->
|
||||
<integer-array translatable="false" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate">
|
||||
<!--
|
||||
<item>disp0</item>
|
||||
<item>disp1</item>
|
||||
-->
|
||||
</integer-array>
|
||||
|
||||
<integer-array translatable="false" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate">
|
||||
<!--
|
||||
<item>amb0</item>
|
||||
<item>amb1</item>
|
||||
-->
|
||||
</integer-array>
|
||||
|
||||
<!-- Default refresh rate in the high zone defined by brightness and ambient thresholds.
|
||||
If non-positive, then the refresh rate is unchanged even if thresholds are configured. -->
|
||||
<integer name="config_fixedRefreshRateInHighZone">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" />
|
||||
|
||||
@@ -3783,6 +3783,11 @@
|
||||
<java-symbol type="array" name="config_brightnessThresholdsOfPeakRefreshRate" />
|
||||
<java-symbol type="array" name="config_ambientThresholdsOfPeakRefreshRate" />
|
||||
|
||||
<!-- For fixed refresh rate displays in high brightness-->
|
||||
<java-symbol type="integer" name="config_fixedRefreshRateInHighZone" />
|
||||
<java-symbol type="array" name="config_highDisplayBrightnessThresholdsOfFixedRefreshRate" />
|
||||
<java-symbol type="array" name="config_highAmbientBrightnessThresholdsOfFixedRefreshRate" />
|
||||
|
||||
<!-- For Auto-Brightness -->
|
||||
<java-symbol type="string" name="config_displayLightSensorType" />
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
filegroup {
|
||||
name: "services.core-sources-deviceconfig-interface",
|
||||
srcs: [
|
||||
"java/com/android/server/utils/DeviceConfigInterface.java"
|
||||
],
|
||||
}
|
||||
|
||||
filegroup {
|
||||
name: "services.core-sources",
|
||||
srcs: ["java/**/*.java"],
|
||||
|
||||
@@ -46,8 +46,10 @@ import android.view.DisplayInfo;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.display.utils.AmbientFilter;
|
||||
import com.android.server.display.utils.AmbientFilterFactory;
|
||||
import com.android.server.utils.DeviceConfigInterface;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
@@ -64,9 +66,11 @@ public class DisplayModeDirector {
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int MSG_REFRESH_RATE_RANGE_CHANGED = 1;
|
||||
private static final int MSG_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
|
||||
private static final int MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED = 2;
|
||||
private static final int MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED = 3;
|
||||
private static final int MSG_REFRESH_RATE_IN_ZONE_CHANGED = 4;
|
||||
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;
|
||||
|
||||
// Special ID used to indicate that given vote is to be applied globally, rather than to a
|
||||
// specific display.
|
||||
@@ -79,6 +83,13 @@ public class DisplayModeDirector {
|
||||
private final Context mContext;
|
||||
|
||||
private final DisplayModeDirectorHandler mHandler;
|
||||
private final Injector mInjector;
|
||||
|
||||
private final AppRequestObserver mAppRequestObserver;
|
||||
private final SettingsObserver mSettingsObserver;
|
||||
private final DisplayObserver mDisplayObserver;
|
||||
private final DeviceConfigInterface mDeviceConfig;
|
||||
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
|
||||
|
||||
// A map from the display ID to the collection of votes and their priority. The latter takes
|
||||
// the form of another map from the priority to the vote itself so that each priority is
|
||||
@@ -89,17 +100,19 @@ public class DisplayModeDirector {
|
||||
// A map from the display ID to the default mode of that display.
|
||||
private SparseArray<Display.Mode> mDefaultModeByDisplay;
|
||||
|
||||
private final AppRequestObserver mAppRequestObserver;
|
||||
private final SettingsObserver mSettingsObserver;
|
||||
private final DisplayObserver mDisplayObserver;
|
||||
private BrightnessObserver mBrightnessObserver;
|
||||
|
||||
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
|
||||
private DesiredDisplayModeSpecsListener mDesiredDisplayModeSpecsListener;
|
||||
|
||||
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
|
||||
this(context, handler, new RealInjector());
|
||||
}
|
||||
|
||||
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler,
|
||||
@NonNull Injector injector) {
|
||||
mContext = context;
|
||||
mHandler = new DisplayModeDirectorHandler(handler.getLooper());
|
||||
mInjector = injector;
|
||||
mVotesByDisplay = new SparseArray<>();
|
||||
mSupportedModesByDisplay = new SparseArray<>();
|
||||
mDefaultModeByDisplay = new SparseArray<>();
|
||||
@@ -108,6 +121,7 @@ public class DisplayModeDirector {
|
||||
mDisplayObserver = new DisplayObserver(context, handler);
|
||||
mBrightnessObserver = new BrightnessObserver(context, handler);
|
||||
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
|
||||
mDeviceConfig = injector.getDeviceConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,6 +362,23 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Vote for the given display and priority. Intended only for testing purposes.
|
||||
*
|
||||
* @param displayId the display to query for
|
||||
* @param priority the priority of the vote to return
|
||||
* @return the vote corresponding to the given {@code displayId} and {@code priority},
|
||||
* or {@code null} if there isn't one
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
Vote getVote(int displayId, int priority) {
|
||||
synchronized (mLock) {
|
||||
SparseArray<Vote> votes = getVotesLocked(displayId);
|
||||
return votes.get(priority);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the object's state and debug information into the given stream.
|
||||
*
|
||||
@@ -465,6 +496,17 @@ public class DisplayModeDirector {
|
||||
mBrightnessObserver = brightnessObserver;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
BrightnessObserver getBrightnessObserver() {
|
||||
return mBrightnessObserver;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
SettingsObserver getSettingsObserver() {
|
||||
return mSettingsObserver;
|
||||
}
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
|
||||
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
|
||||
@@ -493,16 +535,35 @@ public class DisplayModeDirector {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
|
||||
case MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED: {
|
||||
Pair<int[], int[]> thresholds = (Pair<int[], int[]>) msg.obj;
|
||||
mBrightnessObserver.onDeviceConfigLowBrightnessThresholdsChanged(
|
||||
thresholds.first, thresholds.second);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED: {
|
||||
int refreshRateInZone = msg.arg1;
|
||||
mBrightnessObserver.onDeviceConfigRefreshRateInLowZoneChanged(
|
||||
refreshRateInZone);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_HIGH_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);
|
||||
}
|
||||
mBrightnessObserver.onDeviceConfigHighBrightnessThresholdsChanged(
|
||||
thresholds.first, thresholds.second);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED: {
|
||||
int refreshRateInZone = msg.arg1;
|
||||
mBrightnessObserver.onDeviceConfigRefreshRateInHighZoneChanged(
|
||||
refreshRateInZone);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED:
|
||||
Float defaultPeakRefreshRate = (Float) msg.obj;
|
||||
@@ -510,12 +571,6 @@ public class DisplayModeDirector {
|
||||
defaultPeakRefreshRate);
|
||||
break;
|
||||
|
||||
case MSG_REFRESH_RATE_IN_ZONE_CHANGED:
|
||||
int refreshRateInZone = msg.arg1;
|
||||
mBrightnessObserver.onDeviceConfigRefreshRateInZoneChanged(
|
||||
refreshRateInZone);
|
||||
break;
|
||||
|
||||
case MSG_REFRESH_RATE_RANGE_CHANGED:
|
||||
DesiredDisplayModeSpecsListener desiredDisplayModeSpecsListener =
|
||||
(DesiredDisplayModeSpecsListener) msg.obj;
|
||||
@@ -685,10 +740,11 @@ public class DisplayModeDirector {
|
||||
// by all other considerations. It acts to set a default frame rate for a device.
|
||||
public static final int PRIORITY_DEFAULT_REFRESH_RATE = 0;
|
||||
|
||||
// LOW_BRIGHTNESS votes for a single refresh rate like [60,60], [90,90] or null.
|
||||
// FLICKER votes for a single refresh rate like [60,60], [90,90] or null.
|
||||
// If the higher voters result is a range, it will fix the rate to a single choice.
|
||||
// It's used to avoid rate switch in certain conditions.
|
||||
public static final int PRIORITY_LOW_BRIGHTNESS = 1;
|
||||
// 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 = 1;
|
||||
|
||||
// SETTING_MIN_REFRESH_RATE is used to propose a lower bound of display refresh rate.
|
||||
// It votes [MIN_REFRESH_RATE, Float.POSITIVE_INFINITY]
|
||||
@@ -761,8 +817,8 @@ public class DisplayModeDirector {
|
||||
switch (priority) {
|
||||
case PRIORITY_DEFAULT_REFRESH_RATE:
|
||||
return "PRIORITY_DEFAULT_REFRESH_RATE";
|
||||
case PRIORITY_LOW_BRIGHTNESS:
|
||||
return "PRIORITY_LOW_BRIGHTNESS";
|
||||
case PRIORITY_FLICKER:
|
||||
return "PRIORITY_FLICKER";
|
||||
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
|
||||
return "PRIORITY_USER_SETTING_MIN_REFRESH_RATE";
|
||||
case PRIORITY_APP_REQUEST_REFRESH_RATE:
|
||||
@@ -787,7 +843,8 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
private final class SettingsObserver extends ContentObserver {
|
||||
@VisibleForTesting
|
||||
final class SettingsObserver extends ContentObserver {
|
||||
private final Uri mPeakRefreshRateSetting =
|
||||
Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
|
||||
private final Uri mMinRefreshRateSetting =
|
||||
@@ -810,8 +867,7 @@ public class DisplayModeDirector {
|
||||
|
||||
public void observe() {
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
cr.registerContentObserver(mPeakRefreshRateSetting, false /*notifyDescendants*/, this,
|
||||
UserHandle.USER_SYSTEM);
|
||||
mInjector.registerPeakRefreshRateObserver(cr, this);
|
||||
cr.registerContentObserver(mMinRefreshRateSetting, false /*notifyDescendants*/, this,
|
||||
UserHandle.USER_SYSTEM);
|
||||
cr.registerContentObserver(mLowPowerModeSetting, false /*notifyDescendants*/, this,
|
||||
@@ -829,6 +885,13 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultRefreshRate(float refreshRate) {
|
||||
synchronized (mLock) {
|
||||
mDefaultRefreshRate = refreshRate;
|
||||
updateRefreshRateSettingLocked();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeviceConfigDefaultPeakRefreshRateChanged(Float defaultPeakRefreshRate) {
|
||||
if (defaultPeakRefreshRate == null) {
|
||||
defaultPeakRefreshRate = (float) mContext.getResources().getInteger(
|
||||
@@ -1033,6 +1096,7 @@ public class DisplayModeDirector {
|
||||
@Override
|
||||
public void onDisplayChanged(int displayId) {
|
||||
updateDisplayModes(displayId);
|
||||
// TODO: Break the coupling between DisplayObserver and BrightnessObserver.
|
||||
mBrightnessObserver.onDisplayChanged(displayId);
|
||||
}
|
||||
|
||||
@@ -1071,15 +1135,16 @@ public class DisplayModeDirector {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public class BrightnessObserver extends ContentObserver {
|
||||
// TODO: brightnessfloat: change this to the float setting
|
||||
private final Uri mDisplayBrightnessSetting =
|
||||
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
|
||||
private final static int LIGHT_SENSOR_RATE_MS = 250;
|
||||
private int[] mDisplayBrightnessThresholds;
|
||||
private int[] mAmbientBrightnessThresholds;
|
||||
private int[] mLowDisplayBrightnessThresholds;
|
||||
private int[] mLowAmbientBrightnessThresholds;
|
||||
private int[] mHighDisplayBrightnessThresholds;
|
||||
private int[] mHighAmbientBrightnessThresholds;
|
||||
// valid threshold if any item from the array >= 0
|
||||
private boolean mShouldObserveDisplayChange;
|
||||
private boolean mShouldObserveAmbientChange;
|
||||
private boolean mShouldObserveDisplayLowChange;
|
||||
private boolean mShouldObserveAmbientLowChange;
|
||||
private boolean mShouldObserveDisplayHighChange;
|
||||
private boolean mShouldObserveAmbientHighChange;
|
||||
|
||||
private SensorManager mSensorManager;
|
||||
private Sensor mLightSensor;
|
||||
@@ -1087,46 +1152,122 @@ public class DisplayModeDirector {
|
||||
// Take it as low brightness before valid sensor data comes
|
||||
private float mAmbientLux = -1.0f;
|
||||
private AmbientFilter mAmbientFilter;
|
||||
private int mBrightness = -1;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
// Enable light sensor only when mShouldObserveAmbientChange is true, screen is on, peak
|
||||
// refresh rate changeable and low power mode off. After initialization, these states will
|
||||
// Enable light sensor only when mShouldObserveAmbientLowChange is true or
|
||||
// mShouldObserveAmbientHighChange is true, screen is on, peak refresh rate
|
||||
// changeable and low power mode off. After initialization, these states will
|
||||
// be updated from the same handler thread.
|
||||
private boolean mScreenOn = false;
|
||||
private boolean mDefaultDisplayOn = false;
|
||||
private boolean mRefreshRateChangeable = false;
|
||||
private boolean mLowPowerModeEnabled = false;
|
||||
|
||||
private int mRefreshRateInZone;
|
||||
private int mRefreshRateInLowZone;
|
||||
private int mRefreshRateInHighZone;
|
||||
|
||||
BrightnessObserver(Context context, Handler handler) {
|
||||
super(handler);
|
||||
mContext = context;
|
||||
mDisplayBrightnessThresholds = context.getResources().getIntArray(
|
||||
mLowDisplayBrightnessThresholds = context.getResources().getIntArray(
|
||||
R.array.config_brightnessThresholdsOfPeakRefreshRate);
|
||||
mAmbientBrightnessThresholds = context.getResources().getIntArray(
|
||||
mLowAmbientBrightnessThresholds = 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");
|
||||
if (mLowDisplayBrightnessThresholds.length != mLowAmbientBrightnessThresholds.length) {
|
||||
throw new RuntimeException("display low brightness threshold array and ambient "
|
||||
+ "brightness threshold array have different length: "
|
||||
+ "displayBrightnessThresholds="
|
||||
+ Arrays.toString(mLowDisplayBrightnessThresholds)
|
||||
+ ", ambientBrightnessThresholds="
|
||||
+ Arrays.toString(mLowAmbientBrightnessThresholds));
|
||||
}
|
||||
|
||||
mHighDisplayBrightnessThresholds = context.getResources().getIntArray(
|
||||
R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
|
||||
mHighAmbientBrightnessThresholds = context.getResources().getIntArray(
|
||||
R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
|
||||
if (mHighDisplayBrightnessThresholds.length
|
||||
!= mHighAmbientBrightnessThresholds.length) {
|
||||
throw new RuntimeException("display high brightness threshold array and ambient "
|
||||
+ "brightness threshold array have different length: "
|
||||
+ "displayBrightnessThresholds="
|
||||
+ Arrays.toString(mHighDisplayBrightnessThresholds)
|
||||
+ ", ambientBrightnessThresholds="
|
||||
+ Arrays.toString(mHighAmbientBrightnessThresholds));
|
||||
}
|
||||
mRefreshRateInHighZone = context.getResources().getInteger(
|
||||
R.integer.config_fixedRefreshRateInHighZone);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the refresh to lock to when in a low brightness zone
|
||||
*/
|
||||
@VisibleForTesting
|
||||
int getRefreshRateInLowZone() {
|
||||
return mRefreshRateInLowZone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the display brightness thresholds for the low brightness zones
|
||||
*/
|
||||
@VisibleForTesting
|
||||
int[] getLowDisplayBrightnessThresholds() {
|
||||
return mLowDisplayBrightnessThresholds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ambient brightness thresholds for the low brightness zones
|
||||
*/
|
||||
@VisibleForTesting
|
||||
int[] getLowAmbientBrightnessThresholds() {
|
||||
return mLowAmbientBrightnessThresholds;
|
||||
}
|
||||
|
||||
public void registerLightSensor(SensorManager sensorManager, Sensor lightSensor) {
|
||||
mSensorManager = sensorManager;
|
||||
mLightSensor = lightSensor;
|
||||
|
||||
mSensorManager.registerListener(mLightSensorListener,
|
||||
mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
|
||||
}
|
||||
|
||||
public void observe(SensorManager sensorManager) {
|
||||
mSensorManager = sensorManager;
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
mBrightness = Settings.System.getIntForUser(cr,
|
||||
Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
|
||||
|
||||
// DeviceConfig is accessible after system ready.
|
||||
int[] brightnessThresholds = mDeviceConfigDisplaySettings.getBrightnessThresholds();
|
||||
int[] ambientThresholds = mDeviceConfigDisplaySettings.getAmbientThresholds();
|
||||
int[] lowDisplayBrightnessThresholds =
|
||||
mDeviceConfigDisplaySettings.getLowDisplayBrightnessThresholds();
|
||||
int[] lowAmbientBrightnessThresholds =
|
||||
mDeviceConfigDisplaySettings.getLowAmbientBrightnessThresholds();
|
||||
|
||||
if (brightnessThresholds != null && ambientThresholds != null
|
||||
&& brightnessThresholds.length == ambientThresholds.length) {
|
||||
mDisplayBrightnessThresholds = brightnessThresholds;
|
||||
mAmbientBrightnessThresholds = ambientThresholds;
|
||||
if (lowDisplayBrightnessThresholds != null && lowAmbientBrightnessThresholds != null
|
||||
&& lowDisplayBrightnessThresholds.length
|
||||
== lowAmbientBrightnessThresholds.length) {
|
||||
mLowDisplayBrightnessThresholds = lowDisplayBrightnessThresholds;
|
||||
mLowAmbientBrightnessThresholds = lowAmbientBrightnessThresholds;
|
||||
}
|
||||
|
||||
mRefreshRateInZone = mDeviceConfigDisplaySettings.getRefreshRateInZone();
|
||||
|
||||
int[] highDisplayBrightnessThresholds =
|
||||
mDeviceConfigDisplaySettings.getHighDisplayBrightnessThresholds();
|
||||
int[] highAmbientBrightnessThresholds =
|
||||
mDeviceConfigDisplaySettings.getHighAmbientBrightnessThresholds();
|
||||
|
||||
if (highDisplayBrightnessThresholds != null && highAmbientBrightnessThresholds != null
|
||||
&& highDisplayBrightnessThresholds.length
|
||||
== highAmbientBrightnessThresholds.length) {
|
||||
mHighDisplayBrightnessThresholds = highDisplayBrightnessThresholds;
|
||||
mHighAmbientBrightnessThresholds = highAmbientBrightnessThresholds;
|
||||
}
|
||||
|
||||
mRefreshRateInLowZone = mDeviceConfigDisplaySettings.getRefreshRateInLowZone();
|
||||
mRefreshRateInHighZone = mDeviceConfigDisplaySettings.getRefreshRateInHighZone();
|
||||
|
||||
restartObserver();
|
||||
mDeviceConfigDisplaySettings.startListening();
|
||||
}
|
||||
@@ -1138,7 +1279,7 @@ public class DisplayModeDirector {
|
||||
updateSensorStatus();
|
||||
if (!changeable) {
|
||||
// Revoke previous vote from BrightnessObserver
|
||||
updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, null);
|
||||
updateVoteLocked(Vote.PRIORITY_FLICKER, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1150,25 +1291,48 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeviceConfigThresholdsChanged(int[] brightnessThresholds,
|
||||
public void onDeviceConfigLowBrightnessThresholdsChanged(int[] displayThresholds,
|
||||
int[] ambientThresholds) {
|
||||
if (brightnessThresholds != null && ambientThresholds != null
|
||||
&& brightnessThresholds.length == ambientThresholds.length) {
|
||||
mDisplayBrightnessThresholds = brightnessThresholds;
|
||||
mAmbientBrightnessThresholds = ambientThresholds;
|
||||
if (displayThresholds != null && ambientThresholds != null
|
||||
&& displayThresholds.length == ambientThresholds.length) {
|
||||
mLowDisplayBrightnessThresholds = displayThresholds;
|
||||
mLowAmbientBrightnessThresholds = ambientThresholds;
|
||||
} else {
|
||||
// Invalid or empty. Use device default.
|
||||
mDisplayBrightnessThresholds = mContext.getResources().getIntArray(
|
||||
mLowDisplayBrightnessThresholds = mContext.getResources().getIntArray(
|
||||
R.array.config_brightnessThresholdsOfPeakRefreshRate);
|
||||
mAmbientBrightnessThresholds = mContext.getResources().getIntArray(
|
||||
mLowAmbientBrightnessThresholds = mContext.getResources().getIntArray(
|
||||
R.array.config_ambientThresholdsOfPeakRefreshRate);
|
||||
}
|
||||
restartObserver();
|
||||
}
|
||||
|
||||
public void onDeviceConfigRefreshRateInZoneChanged(int refreshRate) {
|
||||
if (refreshRate != mRefreshRateInZone) {
|
||||
mRefreshRateInZone = refreshRate;
|
||||
public void onDeviceConfigRefreshRateInLowZoneChanged(int refreshRate) {
|
||||
if (refreshRate != mRefreshRateInLowZone) {
|
||||
mRefreshRateInLowZone = refreshRate;
|
||||
restartObserver();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeviceConfigHighBrightnessThresholdsChanged(int[] displayThresholds,
|
||||
int[] ambientThresholds) {
|
||||
if (displayThresholds != null && ambientThresholds != null
|
||||
&& displayThresholds.length == ambientThresholds.length) {
|
||||
mHighDisplayBrightnessThresholds = displayThresholds;
|
||||
mHighAmbientBrightnessThresholds = ambientThresholds;
|
||||
} else {
|
||||
// Invalid or empty. Use device default.
|
||||
mHighDisplayBrightnessThresholds = mContext.getResources().getIntArray(
|
||||
R.array.config_highDisplayBrightnessThresholdsOfFixedRefreshRate);
|
||||
mHighAmbientBrightnessThresholds = mContext.getResources().getIntArray(
|
||||
R.array.config_highAmbientBrightnessThresholdsOfFixedRefreshRate);
|
||||
}
|
||||
restartObserver();
|
||||
}
|
||||
|
||||
public void onDeviceConfigRefreshRateInHighZoneChanged(int refreshRate) {
|
||||
if (refreshRate != mRefreshRateInHighZone) {
|
||||
mRefreshRateInHighZone = refreshRate;
|
||||
restartObserver();
|
||||
}
|
||||
}
|
||||
@@ -1176,48 +1340,95 @@ public class DisplayModeDirector {
|
||||
public void dumpLocked(PrintWriter pw) {
|
||||
pw.println(" BrightnessObserver");
|
||||
pw.println(" mAmbientLux: " + mAmbientLux);
|
||||
pw.println(" mRefreshRateInZone: " + mRefreshRateInZone);
|
||||
pw.println(" mBrightness: " + mBrightness);
|
||||
pw.println(" mDefaultDisplayOn: " + mDefaultDisplayOn);
|
||||
pw.println(" mLowPowerModeEnabled: " + mLowPowerModeEnabled);
|
||||
pw.println(" mRefreshRateChangeable: " + mRefreshRateChangeable);
|
||||
pw.println(" mShouldObserveDisplayLowChange: " + mShouldObserveDisplayLowChange);
|
||||
pw.println(" mShouldObserveAmbientLowChange: " + mShouldObserveAmbientLowChange);
|
||||
pw.println(" mRefreshRateInLowZone: " + mRefreshRateInLowZone);
|
||||
|
||||
for (int d: mDisplayBrightnessThresholds) {
|
||||
pw.println(" mDisplayBrightnessThreshold: " + d);
|
||||
for (int d : mLowDisplayBrightnessThresholds) {
|
||||
pw.println(" mDisplayLowBrightnessThreshold: " + d);
|
||||
}
|
||||
|
||||
for (int d: mAmbientBrightnessThresholds) {
|
||||
pw.println(" mAmbientBrightnessThreshold: " + d);
|
||||
for (int d : mLowAmbientBrightnessThresholds) {
|
||||
pw.println(" mAmbientLowBrightnessThreshold: " + d);
|
||||
}
|
||||
|
||||
pw.println(" mShouldObserveDisplayHighChange: " + mShouldObserveDisplayHighChange);
|
||||
pw.println(" mShouldObserveAmbientHighChange: " + mShouldObserveAmbientHighChange);
|
||||
pw.println(" mRefreshRateInHighZone: " + mRefreshRateInHighZone);
|
||||
|
||||
for (int d : mHighDisplayBrightnessThresholds) {
|
||||
pw.println(" mDisplayHighBrightnessThresholds: " + d);
|
||||
}
|
||||
|
||||
for (int d : mHighAmbientBrightnessThresholds) {
|
||||
pw.println(" mAmbientHighBrightnessThresholds: " + d);
|
||||
}
|
||||
|
||||
mLightSensorListener.dumpLocked(pw);
|
||||
|
||||
if (mAmbientFilter != null) {
|
||||
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
|
||||
ipw.setIndent(" ");
|
||||
mAmbientFilter.dump(ipw);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisplayChanged(int displayId) {
|
||||
if (displayId == Display.DEFAULT_DISPLAY) {
|
||||
onScreenOn(isDefaultDisplayOn());
|
||||
updateDefaultDisplayState();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri, int userId) {
|
||||
synchronized (mLock) {
|
||||
onBrightnessChangedLocked();
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
int brightness = Settings.System.getIntForUser(cr,
|
||||
Settings.System.SCREEN_BRIGHTNESS, -1 /*default*/, cr.getUserId());
|
||||
if (brightness != mBrightness) {
|
||||
mBrightness = brightness;
|
||||
onBrightnessChangedLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (mRefreshRateInLowZone > 0) {
|
||||
mShouldObserveDisplayLowChange = hasValidThreshold(
|
||||
mLowDisplayBrightnessThresholds);
|
||||
mShouldObserveAmbientLowChange = hasValidThreshold(
|
||||
mLowAmbientBrightnessThresholds);
|
||||
} else {
|
||||
cr.unregisterContentObserver(this);
|
||||
mShouldObserveDisplayLowChange = false;
|
||||
mShouldObserveAmbientLowChange = false;
|
||||
}
|
||||
|
||||
if (mShouldObserveAmbientChange) {
|
||||
if (mRefreshRateInHighZone > 0) {
|
||||
mShouldObserveDisplayHighChange = hasValidThreshold(
|
||||
mHighDisplayBrightnessThresholds);
|
||||
mShouldObserveAmbientHighChange = hasValidThreshold(
|
||||
mHighAmbientBrightnessThresholds);
|
||||
} else {
|
||||
mShouldObserveDisplayHighChange = false;
|
||||
mShouldObserveAmbientHighChange = false;
|
||||
}
|
||||
|
||||
if (mShouldObserveDisplayLowChange || mShouldObserveDisplayHighChange) {
|
||||
// Content Service does not check if an listener has already been registered.
|
||||
// To ensure only one listener is registered, force an unregistration first.
|
||||
mInjector.unregisterBrightnessObserver(cr, this);
|
||||
mInjector.registerBrightnessObserver(cr, this);
|
||||
} else {
|
||||
mInjector.unregisterBrightnessObserver(cr, this);
|
||||
}
|
||||
|
||||
if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) {
|
||||
Resources resources = mContext.getResources();
|
||||
String lightSensorType = resources.getString(
|
||||
com.android.internal.R.string.config_displayLightSensorType);
|
||||
@@ -1243,8 +1454,6 @@ public class DisplayModeDirector {
|
||||
|
||||
mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res);
|
||||
mLightSensor = lightSensor;
|
||||
|
||||
onScreenOn(isDefaultDisplayOn());
|
||||
}
|
||||
} else {
|
||||
mAmbientFilter = null;
|
||||
@@ -1263,11 +1472,7 @@ public class DisplayModeDirector {
|
||||
* Checks to see if at least one value is positive, in which case it is necessary to listen
|
||||
* to value changes.
|
||||
*/
|
||||
private boolean checkShouldObserve(int[] a) {
|
||||
if (mRefreshRateInZone <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasValidThreshold(int[] a) {
|
||||
for (int d: a) {
|
||||
if (d >= 0) {
|
||||
return true;
|
||||
@@ -1277,13 +1482,13 @@ public class DisplayModeDirector {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isInsideZone(int brightness, float lux) {
|
||||
for (int i = 0; i < mDisplayBrightnessThresholds.length; i++) {
|
||||
int disp = mDisplayBrightnessThresholds[i];
|
||||
int ambi = mAmbientBrightnessThresholds[i];
|
||||
private boolean isInsideLowZone(int brightness, float lux) {
|
||||
for (int i = 0; i < mLowDisplayBrightnessThresholds.length; i++) {
|
||||
int disp = mLowDisplayBrightnessThresholds[i];
|
||||
int ambi = mLowAmbientBrightnessThresholds[i];
|
||||
|
||||
if (disp >= 0 && ambi >= 0) {
|
||||
if (brightness <= disp && mAmbientLux <= ambi) {
|
||||
if (brightness <= disp && lux <= ambi) {
|
||||
return true;
|
||||
}
|
||||
} else if (disp >= 0) {
|
||||
@@ -1291,7 +1496,7 @@ public class DisplayModeDirector {
|
||||
return true;
|
||||
}
|
||||
} else if (ambi >= 0) {
|
||||
if (mAmbientLux <= ambi) {
|
||||
if (lux <= ambi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1299,27 +1504,77 @@ public class DisplayModeDirector {
|
||||
|
||||
return false;
|
||||
}
|
||||
// TODO: brightnessfloat: make it use float not int
|
||||
private void onBrightnessChangedLocked() {
|
||||
int brightness = Settings.System.getInt(mContext.getContentResolver(),
|
||||
Settings.System.SCREEN_BRIGHTNESS, -1);
|
||||
|
||||
private boolean isInsideHighZone(int brightness, float lux) {
|
||||
for (int i = 0; i < mHighDisplayBrightnessThresholds.length; i++) {
|
||||
int disp = mHighDisplayBrightnessThresholds[i];
|
||||
int ambi = mHighAmbientBrightnessThresholds[i];
|
||||
|
||||
if (disp >= 0 && ambi >= 0) {
|
||||
if (brightness >= disp && lux >= ambi) {
|
||||
return true;
|
||||
}
|
||||
} else if (disp >= 0) {
|
||||
if (brightness >= disp) {
|
||||
return true;
|
||||
}
|
||||
} else if (ambi >= 0) {
|
||||
if (lux >= ambi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
private void onBrightnessChangedLocked() {
|
||||
Vote vote = null;
|
||||
boolean insideZone = isInsideZone(brightness, mAmbientLux);
|
||||
if (insideZone) {
|
||||
vote = Vote.forRefreshRates(mRefreshRateInZone, mRefreshRateInZone);
|
||||
|
||||
if (mBrightness < 0) {
|
||||
// Either the setting isn't available or we shouldn't be observing yet anyways.
|
||||
// Either way, just bail out since there's nothing we can do here.
|
||||
return;
|
||||
}
|
||||
|
||||
boolean insideLowZone = hasValidLowZone() && isInsideLowZone(mBrightness, mAmbientLux);
|
||||
if (insideLowZone) {
|
||||
vote = Vote.forRefreshRates(mRefreshRateInLowZone, mRefreshRateInLowZone);
|
||||
}
|
||||
|
||||
boolean insideHighZone = hasValidHighZone()
|
||||
&& isInsideHighZone(mBrightness, mAmbientLux);
|
||||
if (insideHighZone) {
|
||||
vote = Vote.forRefreshRates(mRefreshRateInHighZone, mRefreshRateInHighZone);
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Display brightness " + brightness + ", ambient lux " + mAmbientLux +
|
||||
", Vote " + vote);
|
||||
Slog.d(TAG, "Display brightness " + mBrightness + ", ambient lux " + mAmbientLux
|
||||
+ ", Vote " + vote);
|
||||
}
|
||||
updateVoteLocked(Vote.PRIORITY_LOW_BRIGHTNESS, vote);
|
||||
updateVoteLocked(Vote.PRIORITY_FLICKER, vote);
|
||||
}
|
||||
|
||||
private void onScreenOn(boolean on) {
|
||||
if (mScreenOn != on) {
|
||||
mScreenOn = on;
|
||||
private boolean hasValidLowZone() {
|
||||
return mRefreshRateInLowZone > 0
|
||||
&& (mShouldObserveDisplayLowChange || mShouldObserveAmbientLowChange);
|
||||
}
|
||||
|
||||
private boolean hasValidHighZone() {
|
||||
return mRefreshRateInHighZone > 0
|
||||
&& (mShouldObserveDisplayHighChange || mShouldObserveAmbientHighChange);
|
||||
}
|
||||
|
||||
private void updateDefaultDisplayState() {
|
||||
Display display = mContext.getSystemService(DisplayManager.class)
|
||||
.getDisplay(Display.DEFAULT_DISPLAY);
|
||||
boolean defaultDisplayOn = display != null && display.getState() != Display.STATE_OFF;
|
||||
setDefaultDisplayState(defaultDisplayOn);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setDefaultDisplayState(boolean on) {
|
||||
if (mDefaultDisplayOn != on) {
|
||||
mDefaultDisplayOn = on;
|
||||
updateSensorStatus();
|
||||
}
|
||||
}
|
||||
@@ -1329,8 +1584,8 @@ public class DisplayModeDirector {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mShouldObserveAmbientChange && mScreenOn && !mLowPowerModeEnabled
|
||||
&& mRefreshRateChangeable) {
|
||||
if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange)
|
||||
&& isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) {
|
||||
mSensorManager.registerListener(mLightSensorListener,
|
||||
mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
|
||||
} else {
|
||||
@@ -1339,11 +1594,8 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDefaultDisplayOn() {
|
||||
final Display display = mContext.getSystemService(DisplayManager.class)
|
||||
.getDisplay(Display.DEFAULT_DISPLAY);
|
||||
return display.getState() != Display.STATE_OFF
|
||||
&& mContext.getSystemService(PowerManager.class).isInteractive();
|
||||
private boolean isDeviceActive() {
|
||||
return mDefaultDisplayOn && mInjector.isDeviceInteractive(mContext);
|
||||
}
|
||||
|
||||
private final class LightSensorEventListener implements SensorEventListener {
|
||||
@@ -1361,23 +1613,33 @@ public class DisplayModeDirector {
|
||||
Slog.d(TAG, "On sensor changed: " + mLastSensorData);
|
||||
}
|
||||
|
||||
boolean zoneChanged = isDifferentZone(mLastSensorData, mAmbientLux);
|
||||
if (zoneChanged && mLastSensorData < mAmbientLux) {
|
||||
// Easier to see flicker at lower brightness environment. Forget the history to
|
||||
// get immediate response.
|
||||
mAmbientFilter.clear();
|
||||
boolean lowZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
|
||||
mLowAmbientBrightnessThresholds);
|
||||
boolean highZoneChanged = isDifferentZone(mLastSensorData, mAmbientLux,
|
||||
mHighAmbientBrightnessThresholds);
|
||||
if ((lowZoneChanged && mLastSensorData < mAmbientLux)
|
||||
|| (highZoneChanged && mLastSensorData > mAmbientLux)) {
|
||||
// Easier to see flicker at lower brightness environment or high brightness
|
||||
// environment. Forget the history to get immediate response.
|
||||
if (mAmbientFilter != null) {
|
||||
mAmbientFilter.clear();
|
||||
}
|
||||
}
|
||||
|
||||
long now = SystemClock.uptimeMillis();
|
||||
mAmbientFilter.addValue(now, mLastSensorData);
|
||||
if (mAmbientFilter != null) {
|
||||
mAmbientFilter.addValue(now, mLastSensorData);
|
||||
}
|
||||
|
||||
mHandler.removeCallbacks(mInjectSensorEventRunnable);
|
||||
processSensorData(now);
|
||||
|
||||
if (zoneChanged && mLastSensorData > mAmbientLux) {
|
||||
if ((lowZoneChanged && mLastSensorData > mAmbientLux)
|
||||
|| (highZoneChanged && mLastSensorData < mAmbientLux)) {
|
||||
// Sensor may not report new event if there is no brightness change.
|
||||
// Need to keep querying the temporal filter for the latest estimation,
|
||||
// until enter in higher lux zone or is interrupted by a new sensor event.
|
||||
// until sensor readout and filter estimation are in the same zone or
|
||||
// is interrupted by a new sensor event.
|
||||
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
@@ -1392,17 +1654,19 @@ public class DisplayModeDirector {
|
||||
}
|
||||
|
||||
private void processSensorData(long now) {
|
||||
mAmbientLux = mAmbientFilter.getEstimate(now);
|
||||
if (mAmbientFilter != null) {
|
||||
mAmbientLux = mAmbientFilter.getEstimate(now);
|
||||
} else {
|
||||
mAmbientLux = mLastSensorData;
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
onBrightnessChangedLocked();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDifferentZone(float lux1, float lux2) {
|
||||
for (int z = 0; z < mAmbientBrightnessThresholds.length; z++) {
|
||||
final float boundary = mAmbientBrightnessThresholds[z];
|
||||
|
||||
private boolean isDifferentZone(float lux1, float lux2, int[] luxThresholds) {
|
||||
for (final float boundary : luxThresholds) {
|
||||
// Test each boundary. See if the current value and the new value are at
|
||||
// different sides.
|
||||
if ((lux1 <= boundary && lux2 > boundary)
|
||||
@@ -1422,7 +1686,10 @@ public class DisplayModeDirector {
|
||||
processSensorData(now);
|
||||
|
||||
// Inject next event if there is a possible zone change.
|
||||
if (isDifferentZone(mLastSensorData, mAmbientLux)) {
|
||||
if (isDifferentZone(mLastSensorData, mAmbientLux,
|
||||
mLowAmbientBrightnessThresholds)
|
||||
|| isDifferentZone(mLastSensorData, mAmbientLux,
|
||||
mHighAmbientBrightnessThresholds)) {
|
||||
mHandler.postDelayed(mInjectSensorEventRunnable, INJECT_EVENTS_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
@@ -1435,33 +1702,75 @@ public class DisplayModeDirector {
|
||||
}
|
||||
|
||||
public void startListening() {
|
||||
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
mDeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
BackgroundThread.getExecutor(), this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return null if no such property or wrong format (not comma separated integers).
|
||||
*/
|
||||
public int[] getBrightnessThresholds() {
|
||||
public int[] getLowDisplayBrightnessThresholds() {
|
||||
return getIntArrayProperty(
|
||||
DisplayManager.DeviceConfig.
|
||||
KEY_PEAK_REFRESH_RATE_DISPLAY_BRIGHTNESS_THRESHOLDS);
|
||||
KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return null if no such property or wrong format (not comma separated integers).
|
||||
*/
|
||||
public int[] getAmbientThresholds() {
|
||||
public int[] getLowAmbientBrightnessThresholds() {
|
||||
return getIntArrayProperty(
|
||||
DisplayManager.DeviceConfig.
|
||||
KEY_PEAK_REFRESH_RATE_AMBIENT_BRIGHTNESS_THRESHOLDS);
|
||||
KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS);
|
||||
}
|
||||
|
||||
public int getRefreshRateInLowZone() {
|
||||
int defaultRefreshRateInZone = mContext.getResources().getInteger(
|
||||
R.integer.config_defaultRefreshRateInZone);
|
||||
|
||||
int refreshRate = mDeviceConfig.getInt(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE,
|
||||
defaultRefreshRateInZone);
|
||||
|
||||
return refreshRate;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return null if no such property or wrong format (not comma separated integers).
|
||||
*/
|
||||
public int[] getHighDisplayBrightnessThresholds() {
|
||||
return getIntArrayProperty(
|
||||
DisplayManager.DeviceConfig
|
||||
.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return null if no such property or wrong format (not comma separated integers).
|
||||
*/
|
||||
public int[] getHighAmbientBrightnessThresholds() {
|
||||
return getIntArrayProperty(
|
||||
DisplayManager.DeviceConfig
|
||||
.KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS);
|
||||
}
|
||||
|
||||
public int getRefreshRateInHighZone() {
|
||||
int defaultRefreshRateInZone = mContext.getResources().getInteger(
|
||||
R.integer.config_fixedRefreshRateInHighZone);
|
||||
|
||||
int refreshRate = mDeviceConfig.getInt(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE,
|
||||
defaultRefreshRateInZone);
|
||||
|
||||
return refreshRate;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return null if no such property
|
||||
*/
|
||||
public Float getDefaultPeakRefreshRate() {
|
||||
float defaultPeakRefreshRate = DeviceConfig.getFloat(
|
||||
float defaultPeakRefreshRate = mDeviceConfig.getFloat(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
DisplayManager.DeviceConfig.KEY_PEAK_REFRESH_RATE_DEFAULT, -1);
|
||||
|
||||
@@ -1471,36 +1780,35 @@ public class DisplayModeDirector {
|
||||
return defaultPeakRefreshRate;
|
||||
}
|
||||
|
||||
public int getRefreshRateInZone() {
|
||||
int defaultRefreshRateInZone = mContext.getResources().getInteger(
|
||||
R.integer.config_defaultRefreshRateInZone);
|
||||
|
||||
int refreshRate = DeviceConfig.getInt(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_ZONE,
|
||||
defaultRefreshRateInZone);
|
||||
|
||||
return refreshRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
|
||||
int[] brightnessThresholds = getBrightnessThresholds();
|
||||
int[] ambientThresholds = getAmbientThresholds();
|
||||
Float defaultPeakRefreshRate = getDefaultPeakRefreshRate();
|
||||
int refreshRateInZone = getRefreshRateInZone();
|
||||
|
||||
mHandler.obtainMessage(MSG_BRIGHTNESS_THRESHOLDS_CHANGED,
|
||||
new Pair<int[], int[]>(brightnessThresholds, ambientThresholds))
|
||||
.sendToTarget();
|
||||
mHandler.obtainMessage(MSG_DEFAULT_PEAK_REFRESH_RATE_CHANGED,
|
||||
defaultPeakRefreshRate).sendToTarget();
|
||||
mHandler.obtainMessage(MSG_REFRESH_RATE_IN_ZONE_CHANGED, refreshRateInZone,
|
||||
0).sendToTarget();
|
||||
|
||||
int[] lowDisplayBrightnessThresholds = getLowDisplayBrightnessThresholds();
|
||||
int[] lowAmbientBrightnessThresholds = getLowAmbientBrightnessThresholds();
|
||||
int refreshRateInLowZone = getRefreshRateInLowZone();
|
||||
|
||||
mHandler.obtainMessage(MSG_LOW_BRIGHTNESS_THRESHOLDS_CHANGED,
|
||||
new Pair<>(lowDisplayBrightnessThresholds, lowAmbientBrightnessThresholds))
|
||||
.sendToTarget();
|
||||
mHandler.obtainMessage(MSG_REFRESH_RATE_IN_LOW_ZONE_CHANGED, refreshRateInLowZone, 0)
|
||||
.sendToTarget();
|
||||
|
||||
int[] highDisplayBrightnessThresholds = getHighDisplayBrightnessThresholds();
|
||||
int[] highAmbientBrightnessThresholds = getHighAmbientBrightnessThresholds();
|
||||
int refreshRateInHighZone = getRefreshRateInHighZone();
|
||||
|
||||
mHandler.obtainMessage(MSG_HIGH_BRIGHTNESS_THRESHOLDS_CHANGED,
|
||||
new Pair<>(highDisplayBrightnessThresholds, highAmbientBrightnessThresholds))
|
||||
.sendToTarget();
|
||||
mHandler.obtainMessage(MSG_REFRESH_RATE_IN_HIGH_ZONE_CHANGED, refreshRateInHighZone, 0)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
private int[] getIntArrayProperty(String prop) {
|
||||
String strArray = DeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
|
||||
String strArray = mDeviceConfig.getString(DeviceConfig.NAMESPACE_DISPLAY_MANAGER, prop,
|
||||
null);
|
||||
|
||||
if (strArray != null) {
|
||||
@@ -1527,4 +1835,59 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
interface Injector {
|
||||
// TODO: brightnessfloat: change this to the float setting
|
||||
Uri DISPLAY_BRIGHTNESS_URI = Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
|
||||
Uri PEAK_REFRESH_RATE_URI = Settings.System.getUriFor(Settings.System.PEAK_REFRESH_RATE);
|
||||
|
||||
@NonNull
|
||||
DeviceConfigInterface getDeviceConfig();
|
||||
|
||||
void registerBrightnessObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer);
|
||||
|
||||
void unregisterBrightnessObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer);
|
||||
|
||||
void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer);
|
||||
|
||||
boolean isDeviceInteractive(@NonNull Context context);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static class RealInjector implements Injector {
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public DeviceConfigInterface getDeviceConfig() {
|
||||
return DeviceConfigInterface.REAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBrightnessObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer) {
|
||||
cr.registerContentObserver(DISPLAY_BRIGHTNESS_URI, false /*notifyDescendants*/,
|
||||
observer, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer) {
|
||||
cr.unregisterContentObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer) {
|
||||
cr.registerContentObserver(PEAK_REFRESH_RATE_URI, false /*notifyDescendants*/,
|
||||
observer, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeviceInteractive(@NonNull Context ctx) {
|
||||
return ctx.getSystemService(PowerManager.class).isInteractive();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.wm.utils;
|
||||
package com.android.server.utils;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -53,6 +53,11 @@ public interface DeviceConfigInterface {
|
||||
*/
|
||||
boolean getBoolean(@NonNull String namespace, @NonNull String name, boolean defaultValue);
|
||||
|
||||
/**
|
||||
* @see DeviceConfig#getFloat
|
||||
*/
|
||||
float getFloat(@NonNull String namespace, @NonNull String name, float defaultValue);
|
||||
|
||||
/**
|
||||
* @see DeviceConfig#addOnPropertiesChangedListener
|
||||
*/
|
||||
@@ -95,6 +100,12 @@ public interface DeviceConfigInterface {
|
||||
return DeviceConfig.getBoolean(namespace, name, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(@NonNull String namespace, @NonNull String name,
|
||||
float defaultValue) {
|
||||
return DeviceConfig.getFloat(namespace, name, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnPropertiesChangedListener(String namespace, Executor executor,
|
||||
DeviceConfig.OnPropertiesChangedListener listener) {
|
||||
@@ -27,7 +27,7 @@ import android.util.ArraySet;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.server.wm.utils.DeviceConfigInterface;
|
||||
import com.android.server.utils.DeviceConfigInterface;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.provider.AndroidDeviceConfig;
|
||||
import android.provider.DeviceConfig;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.wm.utils.DeviceConfigInterface;
|
||||
import com.android.server.utils.DeviceConfigInterface;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -282,8 +282,8 @@ import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
|
||||
import com.android.server.power.ShutdownThread;
|
||||
import com.android.server.protolog.ProtoLogImpl;
|
||||
import com.android.server.protolog.common.ProtoLog;
|
||||
import com.android.server.utils.DeviceConfigInterface;
|
||||
import com.android.server.utils.PriorityDump;
|
||||
import com.android.server.wm.utils.DeviceConfigInterface;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.DataInputStream;
|
||||
|
||||
@@ -48,7 +48,6 @@ android_test {
|
||||
// TODO: remove once Android migrates to JUnit 4.12,
|
||||
// which provides assertThrows
|
||||
"testng",
|
||||
|
||||
],
|
||||
|
||||
aidl: {
|
||||
@@ -110,6 +109,7 @@ java_library {
|
||||
"utils/**/*.java",
|
||||
"utils/**/*.kt",
|
||||
"utils-mockito/**/*.kt",
|
||||
":services.core-sources-deviceconfig-interface",
|
||||
],
|
||||
static_libs: [
|
||||
"junit",
|
||||
@@ -126,6 +126,7 @@ java_library {
|
||||
"utils/**/*.java",
|
||||
"utils/**/*.kt",
|
||||
"utils-mockito/**/*.kt",
|
||||
":services.core-sources-deviceconfig-interface",
|
||||
],
|
||||
static_libs: [
|
||||
"junit",
|
||||
|
||||
@@ -16,49 +16,99 @@
|
||||
|
||||
package com.android.server.display;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
|
||||
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
|
||||
|
||||
import static com.android.server.display.DisplayModeDirector.Vote.PRIORITY_FLICKER;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
import com.android.server.display.DisplayModeDirector.BrightnessObserver;
|
||||
import com.android.server.display.DisplayModeDirector.DesiredDisplayModeSpecs;
|
||||
import com.android.server.display.DisplayModeDirector.Vote;
|
||||
import com.android.server.testutils.FakeDeviceConfigInterface;
|
||||
|
||||
import com.google.common.truth.Truth;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class DisplayModeDirectorTest {
|
||||
// The tolerance within which we consider something approximately equals.
|
||||
private static final String TAG = "DisplayModeDirectorTest";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final float FLOAT_TOLERANCE = 0.01f;
|
||||
|
||||
private Context mContext;
|
||||
private FakesInjector mInjector;
|
||||
private Handler mHandler;
|
||||
@Rule
|
||||
public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
mContext = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
|
||||
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
|
||||
when(mContext.getContentResolver()).thenReturn(resolver);
|
||||
mInjector = new FakesInjector();
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
private DisplayModeDirector createDirectorFromRefreshRateArray(
|
||||
float[] refreshRates, int baseModeId) {
|
||||
DisplayModeDirector director =
|
||||
new DisplayModeDirector(mContext, new Handler(Looper.getMainLooper()));
|
||||
new DisplayModeDirector(mContext, mHandler, mInjector);
|
||||
int displayId = 0;
|
||||
Display.Mode[] modes = new Display.Mode[refreshRates.length];
|
||||
for (int i = 0; i < refreshRates.length; i++) {
|
||||
@@ -159,9 +209,9 @@ public class DisplayModeDirectorTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBrightnessHasLowerPriorityThanUser() {
|
||||
assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
|
||||
assertTrue(Vote.PRIORITY_LOW_BRIGHTNESS < Vote.PRIORITY_APP_REQUEST_SIZE);
|
||||
public void testFlickerHasLowerPriorityThanUser() {
|
||||
assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_REFRESH_RATE);
|
||||
assertTrue(PRIORITY_FLICKER < Vote.PRIORITY_APP_REQUEST_SIZE);
|
||||
|
||||
int displayId = 0;
|
||||
DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
|
||||
@@ -169,7 +219,7 @@ public class DisplayModeDirectorTest {
|
||||
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
|
||||
votesByDisplay.put(displayId, votes);
|
||||
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
|
||||
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
|
||||
votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
|
||||
director.injectVotesByDisplay(votesByDisplay);
|
||||
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
|
||||
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
|
||||
@@ -177,7 +227,7 @@ public class DisplayModeDirectorTest {
|
||||
|
||||
votes.clear();
|
||||
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 90));
|
||||
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
|
||||
votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
|
||||
director.injectVotesByDisplay(votesByDisplay);
|
||||
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
|
||||
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
|
||||
@@ -185,7 +235,7 @@ public class DisplayModeDirectorTest {
|
||||
|
||||
votes.clear();
|
||||
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(90, 90));
|
||||
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
|
||||
votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
|
||||
director.injectVotesByDisplay(votesByDisplay);
|
||||
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
|
||||
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(90);
|
||||
@@ -193,7 +243,7 @@ public class DisplayModeDirectorTest {
|
||||
|
||||
votes.clear();
|
||||
votes.put(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE, Vote.forRefreshRates(60, 60));
|
||||
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(90, 90));
|
||||
votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(90, 90));
|
||||
director.injectVotesByDisplay(votesByDisplay);
|
||||
desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
|
||||
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
|
||||
@@ -202,10 +252,10 @@ public class DisplayModeDirectorTest {
|
||||
|
||||
@Test
|
||||
public void testAppRequestRefreshRateRange() {
|
||||
// Confirm that the app request range doesn't include low brightness or min refresh rate
|
||||
// settings, but does include everything else.
|
||||
// Confirm that the app request range doesn't include flicker or min refresh rate settings,
|
||||
// but does include everything else.
|
||||
assertTrue(
|
||||
Vote.PRIORITY_LOW_BRIGHTNESS < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
|
||||
PRIORITY_FLICKER < Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
|
||||
assertTrue(Vote.PRIORITY_USER_SETTING_MIN_REFRESH_RATE
|
||||
< Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
|
||||
assertTrue(Vote.PRIORITY_APP_REQUEST_REFRESH_RATE
|
||||
@@ -216,7 +266,7 @@ public class DisplayModeDirectorTest {
|
||||
SparseArray<Vote> votes = new SparseArray<>();
|
||||
SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
|
||||
votesByDisplay.put(displayId, votes);
|
||||
votes.put(Vote.PRIORITY_LOW_BRIGHTNESS, Vote.forRefreshRates(60, 60));
|
||||
votes.put(PRIORITY_FLICKER, Vote.forRefreshRates(60, 60));
|
||||
director.injectVotesByDisplay(votesByDisplay);
|
||||
DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(displayId);
|
||||
Truth.assertThat(desiredSpecs.primaryRefreshRateRange.min).isWithin(FLOAT_TOLERANCE).of(60);
|
||||
@@ -302,4 +352,343 @@ public class DisplayModeDirectorTest {
|
||||
verifyBrightnessObserverCall(director, 90, 90, 0, 90, 90);
|
||||
verifyBrightnessObserverCall(director, 120, 90, 0, 120, 90);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBrightnessObserverGetsUpdatedRefreshRatesForZone() {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
|
||||
SensorManager sensorManager = createMockSensorManager(createLightSensor());
|
||||
|
||||
final int initialRefreshRate = 60;
|
||||
mInjector.getDeviceConfig().setRefreshRateInLowZone(initialRefreshRate);
|
||||
director.start(sensorManager);
|
||||
assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
|
||||
.isEqualTo(initialRefreshRate);
|
||||
|
||||
final int updatedRefreshRate = 90;
|
||||
mInjector.getDeviceConfig().setRefreshRateInLowZone(updatedRefreshRate);
|
||||
// Need to wait for the property change to propagate to the main thread.
|
||||
waitForIdleSync();
|
||||
assertThat(director.getBrightnessObserver().getRefreshRateInLowZone())
|
||||
.isEqualTo(updatedRefreshRate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBrightnessObserverThresholdsInZone() {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, /* baseModeId= */ 0);
|
||||
SensorManager sensorManager = createMockSensorManager(createLightSensor());
|
||||
|
||||
final int[] initialDisplayThresholds = { 10 };
|
||||
final int[] initialAmbientThresholds = { 20 };
|
||||
|
||||
final FakeDeviceConfig config = mInjector.getDeviceConfig();
|
||||
config.setLowDisplayBrightnessThresholds(initialDisplayThresholds);
|
||||
config.setLowAmbientBrightnessThresholds(initialAmbientThresholds);
|
||||
director.start(sensorManager);
|
||||
|
||||
assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
|
||||
.isEqualTo(initialDisplayThresholds);
|
||||
assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
|
||||
.isEqualTo(initialAmbientThresholds);
|
||||
|
||||
final int[] updatedDisplayThresholds = { 9, 14 };
|
||||
final int[] updatedAmbientThresholds = { -1, 19 };
|
||||
config.setLowDisplayBrightnessThresholds(updatedDisplayThresholds);
|
||||
config.setLowAmbientBrightnessThresholds(updatedAmbientThresholds);
|
||||
// Need to wait for the property change to propagate to the main thread.
|
||||
waitForIdleSync();
|
||||
assertThat(director.getBrightnessObserver().getLowDisplayBrightnessThresholds())
|
||||
.isEqualTo(updatedDisplayThresholds);
|
||||
assertThat(director.getBrightnessObserver().getLowAmbientBrightnessThresholds())
|
||||
.isEqualTo(updatedAmbientThresholds);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockFpsForLowZone() throws Exception {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
|
||||
setPeakRefreshRate(90);
|
||||
director.getSettingsObserver().setDefaultRefreshRate(90);
|
||||
director.getBrightnessObserver().setDefaultDisplayState(true);
|
||||
|
||||
final FakeDeviceConfig config = mInjector.getDeviceConfig();
|
||||
config.setRefreshRateInLowZone(90);
|
||||
config.setLowDisplayBrightnessThresholds(new int[] { 10 });
|
||||
config.setLowAmbientBrightnessThresholds(new int[] { 20 });
|
||||
|
||||
Sensor lightSensor = createLightSensor();
|
||||
SensorManager sensorManager = createMockSensorManager(lightSensor);
|
||||
|
||||
director.start(sensorManager);
|
||||
|
||||
ArgumentCaptor<SensorEventListener> listenerCaptor =
|
||||
ArgumentCaptor.forClass(SensorEventListener.class);
|
||||
Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
|
||||
.registerListener(
|
||||
listenerCaptor.capture(),
|
||||
eq(lightSensor),
|
||||
anyInt(),
|
||||
any(Handler.class));
|
||||
SensorEventListener listener = listenerCaptor.getValue();
|
||||
|
||||
setBrightness(10);
|
||||
// Sensor reads 20 lux,
|
||||
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 20 /*lux*/));
|
||||
|
||||
Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
|
||||
assertVoteForRefreshRateLocked(vote, 90 /*fps*/);
|
||||
|
||||
setBrightness(125);
|
||||
// Sensor reads 1000 lux,
|
||||
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 1000 /*lux*/));
|
||||
|
||||
vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
|
||||
assertThat(vote).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockFpsForHighZone() throws Exception {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
|
||||
setPeakRefreshRate(90 /*fps*/);
|
||||
director.getSettingsObserver().setDefaultRefreshRate(90);
|
||||
director.getBrightnessObserver().setDefaultDisplayState(true);
|
||||
|
||||
final FakeDeviceConfig config = mInjector.getDeviceConfig();
|
||||
config.setRefreshRateInHighZone(60);
|
||||
config.setHighDisplayBrightnessThresholds(new int[] { 255 });
|
||||
config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
|
||||
|
||||
Sensor lightSensor = createLightSensor();
|
||||
SensorManager sensorManager = createMockSensorManager(lightSensor);
|
||||
|
||||
director.start(sensorManager);
|
||||
|
||||
ArgumentCaptor<SensorEventListener> listenerCaptor =
|
||||
ArgumentCaptor.forClass(SensorEventListener.class);
|
||||
Mockito.verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
|
||||
.registerListener(
|
||||
listenerCaptor.capture(),
|
||||
eq(lightSensor),
|
||||
anyInt(),
|
||||
any(Handler.class));
|
||||
SensorEventListener listener = listenerCaptor.getValue();
|
||||
|
||||
setBrightness(100);
|
||||
// Sensor reads 2000 lux,
|
||||
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 2000));
|
||||
|
||||
Vote vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
|
||||
assertThat(vote).isNull();
|
||||
|
||||
setBrightness(255);
|
||||
// Sensor reads 9000 lux,
|
||||
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 9000));
|
||||
|
||||
vote = director.getVote(Display.DEFAULT_DISPLAY, PRIORITY_FLICKER);
|
||||
assertVoteForRefreshRateLocked(vote, 60 /*fps*/);
|
||||
}
|
||||
|
||||
private void assertVoteForRefreshRateLocked(Vote vote, float refreshRate) {
|
||||
assertThat(vote).isNotNull();
|
||||
final DisplayModeDirector.RefreshRateRange expectedRange =
|
||||
new DisplayModeDirector.RefreshRateRange(refreshRate, refreshRate);
|
||||
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
|
||||
}
|
||||
|
||||
private static class FakeDeviceConfig extends FakeDeviceConfigInterface {
|
||||
@Override
|
||||
public String getProperty(String namespace, String name) {
|
||||
Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
|
||||
return super.getProperty(namespace, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnPropertiesChangedListener(
|
||||
String namespace,
|
||||
Executor executor,
|
||||
DeviceConfig.OnPropertiesChangedListener listener) {
|
||||
Preconditions.checkArgument(DeviceConfig.NAMESPACE_DISPLAY_MANAGER.equals(namespace));
|
||||
super.addOnPropertiesChangedListener(namespace, executor, listener);
|
||||
}
|
||||
|
||||
void setRefreshRateInLowZone(int fps) {
|
||||
putPropertyAndNotify(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_LOW_ZONE,
|
||||
String.valueOf(fps));
|
||||
}
|
||||
|
||||
void setLowDisplayBrightnessThresholds(int[] brightnessThresholds) {
|
||||
String thresholds = toPropertyValue(brightnessThresholds);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Brightness Thresholds = " + thresholds);
|
||||
}
|
||||
|
||||
putPropertyAndNotify(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
KEY_FIXED_REFRESH_RATE_LOW_DISPLAY_BRIGHTNESS_THRESHOLDS,
|
||||
thresholds);
|
||||
}
|
||||
|
||||
void setLowAmbientBrightnessThresholds(int[] ambientThresholds) {
|
||||
String thresholds = toPropertyValue(ambientThresholds);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Ambient Thresholds = " + thresholds);
|
||||
}
|
||||
|
||||
putPropertyAndNotify(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
KEY_FIXED_REFRESH_RATE_LOW_AMBIENT_BRIGHTNESS_THRESHOLDS,
|
||||
thresholds);
|
||||
}
|
||||
|
||||
void setRefreshRateInHighZone(int fps) {
|
||||
putPropertyAndNotify(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER, KEY_REFRESH_RATE_IN_HIGH_ZONE,
|
||||
String.valueOf(fps));
|
||||
}
|
||||
|
||||
void setHighDisplayBrightnessThresholds(int[] brightnessThresholds) {
|
||||
String thresholds = toPropertyValue(brightnessThresholds);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Brightness Thresholds = " + thresholds);
|
||||
}
|
||||
|
||||
putPropertyAndNotify(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
KEY_FIXED_REFRESH_RATE_HIGH_DISPLAY_BRIGHTNESS_THRESHOLDS,
|
||||
thresholds);
|
||||
}
|
||||
|
||||
void setHighAmbientBrightnessThresholds(int[] ambientThresholds) {
|
||||
String thresholds = toPropertyValue(ambientThresholds);
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.e(TAG, "Ambient Thresholds = " + thresholds);
|
||||
}
|
||||
|
||||
putPropertyAndNotify(
|
||||
DeviceConfig.NAMESPACE_DISPLAY_MANAGER,
|
||||
KEY_FIXED_REFRESH_RATE_HIGH_AMBIENT_BRIGHTNESS_THRESHOLDS,
|
||||
thresholds);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static String toPropertyValue(@NonNull int[] intArray) {
|
||||
return Arrays.stream(intArray)
|
||||
.mapToObj(Integer::toString)
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
}
|
||||
|
||||
private void setBrightness(int brightness) {
|
||||
Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS,
|
||||
brightness);
|
||||
mInjector.notifyBrightnessChanged();
|
||||
waitForIdleSync();
|
||||
}
|
||||
|
||||
private void setPeakRefreshRate(float fps) {
|
||||
Settings.System.putFloat(mContext.getContentResolver(), Settings.System.PEAK_REFRESH_RATE,
|
||||
fps);
|
||||
mInjector.notifyPeakRefreshRateChanged();
|
||||
waitForIdleSync();
|
||||
}
|
||||
|
||||
private static SensorManager createMockSensorManager(Sensor... sensors) {
|
||||
SensorManager sensorManager = Mockito.mock(SensorManager.class);
|
||||
when(sensorManager.getSensorList(anyInt())).then((invocation) -> {
|
||||
List<Sensor> requestedSensors = new ArrayList<>();
|
||||
int type = invocation.getArgument(0);
|
||||
for (Sensor sensor : sensors) {
|
||||
if (sensor.getType() == type || type == Sensor.TYPE_ALL) {
|
||||
requestedSensors.add(sensor);
|
||||
}
|
||||
}
|
||||
return requestedSensors;
|
||||
});
|
||||
|
||||
when(sensorManager.getDefaultSensor(anyInt())).then((invocation) -> {
|
||||
int type = invocation.getArgument(0);
|
||||
for (Sensor sensor : sensors) {
|
||||
if (sensor.getType() == type) {
|
||||
return sensor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
return sensorManager;
|
||||
}
|
||||
|
||||
private static Sensor createLightSensor() {
|
||||
try {
|
||||
return TestUtils.createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
|
||||
} catch (Exception e) {
|
||||
// There's nothing we can do if this fails, just throw a RuntimeException so that we
|
||||
// don't have to mark every function that might call this as throwing Exception
|
||||
throw new RuntimeException("Failed to create a light sensor", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void waitForIdleSync() {
|
||||
mHandler.runWithScissors(() -> { }, 500 /*timeout*/);
|
||||
}
|
||||
|
||||
static class FakesInjector implements DisplayModeDirector.Injector {
|
||||
private final FakeDeviceConfig mDeviceConfig;
|
||||
private ContentObserver mBrightnessObserver;
|
||||
private ContentObserver mPeakRefreshRateObserver;
|
||||
|
||||
FakesInjector() {
|
||||
mDeviceConfig = new FakeDeviceConfig();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public FakeDeviceConfig getDeviceConfig() {
|
||||
return mDeviceConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBrightnessObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer) {
|
||||
if (mBrightnessObserver != null) {
|
||||
throw new IllegalStateException("Tried to register a second brightness observer");
|
||||
}
|
||||
mBrightnessObserver = observer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterBrightnessObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer) {
|
||||
mBrightnessObserver = null;
|
||||
}
|
||||
|
||||
void notifyBrightnessChanged() {
|
||||
if (mBrightnessObserver != null) {
|
||||
mBrightnessObserver.dispatchChange(false /*selfChange*/, DISPLAY_BRIGHTNESS_URI);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPeakRefreshRateObserver(@NonNull ContentResolver cr,
|
||||
@NonNull ContentObserver observer) {
|
||||
mPeakRefreshRateObserver = observer;
|
||||
}
|
||||
|
||||
void notifyPeakRefreshRateChanged() {
|
||||
if (mPeakRefreshRateObserver != null) {
|
||||
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
|
||||
PEAK_REFRESH_RATE_URI);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeviceInteractive(@NonNull Context context) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.wm.utils;
|
||||
package com.android.server.testutils;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.provider.DeviceConfig;
|
||||
@@ -22,6 +22,7 @@ import android.util.ArrayMap;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.utils.DeviceConfigInterface;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.HashMap;
|
||||
@@ -121,6 +122,19 @@ public class FakeDeviceConfigInterface implements DeviceConfigInterface {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(String namespace, String name, float defaultValue) {
|
||||
String value = getProperty(namespace, name);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Float.parseFloat(value);
|
||||
} catch (NumberFormatException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String namespace, String name, boolean defaultValue) {
|
||||
String value = getProperty(namespace, name);
|
||||
@@ -31,7 +31,7 @@ import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.wm.utils.FakeDeviceConfigInterface;
|
||||
import com.android.server.testutils.FakeDeviceConfigInterface;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -32,7 +32,7 @@ import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.server.wm.utils.FakeDeviceConfigInterface;
|
||||
import com.android.server.testutils.FakeDeviceConfigInterface;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
@@ -91,6 +91,14 @@ public class FakeSettingsProvider extends MockContentProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link org.junit.rules.TestRule} that makes sure {@link #clearSettingsProvider()}
|
||||
* is triggered before and after each test.
|
||||
*/
|
||||
public static FakeSettingsProviderRule rule() {
|
||||
return new FakeSettingsProviderRule();
|
||||
}
|
||||
|
||||
/**
|
||||
* This needs to be called before and after using the FakeSettingsProvider class.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.util.test;
|
||||
|
||||
import android.content.Context;
|
||||
import android.provider.Settings;
|
||||
import android.test.mock.MockContentResolver;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
/**
|
||||
* JUnit Rule helps keeping test {@link FakeSettingsProvider} clean.
|
||||
*
|
||||
* <p>It clears {@link FakeSettingsProvider} before and after each test. Example use:
|
||||
* <pre class="code"><code class="java">
|
||||
* public class ExampleTest {
|
||||
*
|
||||
* @Rule public FakeSettingsProviderRule rule = FakeSettingsProvider.rule();
|
||||
*
|
||||
* @Test
|
||||
* public void shouldDoSomething() {
|
||||
* ContextResolver cr = rule.mockContentResolver(mContext);
|
||||
* Settings.Global.putInt(cr, "my_setting_name", 1);
|
||||
* // Test code relying on my_setting_name value using cr
|
||||
* }
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* @see FakeSettingsProvider
|
||||
*/
|
||||
public final class FakeSettingsProviderRule implements TestRule {
|
||||
|
||||
/** Prevent initialization outside {@link FakeSettingsProvider}. */
|
||||
FakeSettingsProviderRule() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link MockContentResolver} that uses the {@link FakeSettingsProvider} as the
|
||||
* {@link Settings#AUTHORITY} provider.
|
||||
*/
|
||||
public MockContentResolver mockContentResolver(Context context) {
|
||||
MockContentResolver contentResolver = new MockContentResolver(context);
|
||||
contentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
|
||||
return contentResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return new Statement() {
|
||||
public void evaluate() throws Throwable {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
try {
|
||||
base.evaluate();
|
||||
} finally {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user