Specify refresh rate limits for sensors in config.
Some sensors can limit the range of supported refresh rate when
enabled. This change adds a way to specify that limit withing the
display device config file.
Bug: 175793106
Test: Verify that when sensor is enabled, there is an additional
refresh rate vote for the rate specified in config file.
Test: atest DisplayModeDirectorTest, LocalDisplayAdapterTest
Change-Id: Id210c25fe56cd5353a2436b9b97f2ad01980e465
This commit is contained in:
@@ -22,12 +22,15 @@ import android.hardware.SensorManager;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.util.IntArray;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Display manager local system service interface.
|
||||
*
|
||||
@@ -292,6 +295,23 @@ public abstract class DisplayManagerInternal {
|
||||
@DisplayManager.SwitchingType
|
||||
public abstract int getRefreshRateSwitchingType();
|
||||
|
||||
/**
|
||||
* Return the refresh rate restriction for the specified display and sensor pairing. If the
|
||||
* specified sensor is identified as an associated sensor in the specified display's
|
||||
* display-device-config file, then return any refresh rate restrictions that it might specify.
|
||||
* If no restriction is specified, or the sensor is not associated with the display, then null
|
||||
* will be returned.
|
||||
*
|
||||
* @param displayId The display to check against.
|
||||
* @param name The name of the sensor.
|
||||
* @param type The type of sensor.
|
||||
*
|
||||
* @return The min/max refresh-rate restriction as a {@link Pair} of floats, or null if not
|
||||
* restricted.
|
||||
*/
|
||||
public abstract RefreshRateRange getRefreshRateForDisplayAndSensor(
|
||||
int displayId, String name, String type);
|
||||
|
||||
/**
|
||||
* Describes the requested power state of the display.
|
||||
*
|
||||
@@ -527,4 +547,70 @@ public abstract class DisplayManagerInternal {
|
||||
*/
|
||||
void onDisplayGroupChanged(int groupId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about the min and max refresh rate DM would like to set the display to.
|
||||
*/
|
||||
public static final class RefreshRateRange {
|
||||
public static final String TAG = "RefreshRateRange";
|
||||
|
||||
// The tolerance within which we consider something approximately equals.
|
||||
public static final float FLOAT_TOLERANCE = 0.01f;
|
||||
|
||||
/**
|
||||
* The lowest desired refresh rate.
|
||||
*/
|
||||
public float min;
|
||||
|
||||
/**
|
||||
* The highest desired refresh rate.
|
||||
*/
|
||||
public float max;
|
||||
|
||||
public RefreshRateRange() {}
|
||||
|
||||
public RefreshRateRange(float min, float max) {
|
||||
if (min < 0 || max < 0 || min > max + FLOAT_TOLERANCE) {
|
||||
Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
|
||||
+ min + " " + max);
|
||||
this.min = this.max = 0;
|
||||
return;
|
||||
}
|
||||
if (min > max) {
|
||||
// Min and max are within epsilon of each other, but in the wrong order.
|
||||
float t = min;
|
||||
min = max;
|
||||
max = t;
|
||||
}
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the two objects have the same values.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(other instanceof RefreshRateRange)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefreshRateRange refreshRateRange = (RefreshRateRange) other;
|
||||
return (min == refreshRateRange.min && max == refreshRateRange.max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(min, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + min + " " + max + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Environment;
|
||||
import android.os.PowerManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Slog;
|
||||
import android.util.Spline;
|
||||
@@ -34,6 +35,7 @@ import com.android.server.display.config.HbmTiming;
|
||||
import com.android.server.display.config.HighBrightnessMode;
|
||||
import com.android.server.display.config.NitsMap;
|
||||
import com.android.server.display.config.Point;
|
||||
import com.android.server.display.config.RefreshRateRange;
|
||||
import com.android.server.display.config.SensorDetails;
|
||||
import com.android.server.display.config.XmlParser;
|
||||
|
||||
@@ -79,10 +81,10 @@ public class DisplayDeviceConfig {
|
||||
private final Context mContext;
|
||||
|
||||
// The details of the ambient light sensor associated with this display.
|
||||
private final SensorIdentifier mAmbientLightSensor = new SensorIdentifier();
|
||||
private final SensorData mAmbientLightSensor = new SensorData();
|
||||
|
||||
// The details of the proximity sensor associated with this display.
|
||||
private final SensorIdentifier mProximitySensor = new SensorIdentifier();
|
||||
private final SensorData mProximitySensor = new SensorData();
|
||||
|
||||
// Nits and backlight values that are loaded from either the display device config file, or
|
||||
// config.xml. These are the raw values and just used for the dumpsys
|
||||
@@ -113,6 +115,7 @@ public class DisplayDeviceConfig {
|
||||
private List<String> mQuirks;
|
||||
private boolean mIsHighBrightnessModeEnabled = false;
|
||||
private HighBrightnessModeData mHbmData;
|
||||
private String mLoadedFrom = null;
|
||||
|
||||
private DisplayDeviceConfig(Context context) {
|
||||
mContext = context;
|
||||
@@ -273,11 +276,11 @@ public class DisplayDeviceConfig {
|
||||
return mBrightnessRampSlowIncrease;
|
||||
}
|
||||
|
||||
SensorIdentifier getAmbientLightSensor() {
|
||||
SensorData getAmbientLightSensor() {
|
||||
return mAmbientLightSensor;
|
||||
}
|
||||
|
||||
SensorIdentifier getProximitySensor() {
|
||||
SensorData getProximitySensor() {
|
||||
return mProximitySensor;
|
||||
}
|
||||
|
||||
@@ -306,7 +309,8 @@ public class DisplayDeviceConfig {
|
||||
@Override
|
||||
public String toString() {
|
||||
String str = "DisplayDeviceConfig{"
|
||||
+ "mBacklight=" + Arrays.toString(mBacklight)
|
||||
+ "mLoadedFrom=" + mLoadedFrom
|
||||
+ ", mBacklight=" + Arrays.toString(mBacklight)
|
||||
+ ", mNits=" + Arrays.toString(mNits)
|
||||
+ ", mRawBacklight=" + Arrays.toString(mRawBacklight)
|
||||
+ ", mRawNits=" + Arrays.toString(mRawNits)
|
||||
@@ -336,9 +340,8 @@ public class DisplayDeviceConfig {
|
||||
final String filename = String.format(CONFIG_FILE_FORMAT, suffix);
|
||||
final File filePath = Environment.buildPath(
|
||||
baseDirectory, ETC_DIR, DISPLAY_CONFIG_DIR, filename);
|
||||
if (filePath.exists()) {
|
||||
final DisplayDeviceConfig config = new DisplayDeviceConfig(context);
|
||||
config.initFromFile(filePath);
|
||||
final DisplayDeviceConfig config = new DisplayDeviceConfig(context);
|
||||
if (config.initFromFile(filePath)) {
|
||||
return config;
|
||||
}
|
||||
return null;
|
||||
@@ -356,15 +359,15 @@ public class DisplayDeviceConfig {
|
||||
return config;
|
||||
}
|
||||
|
||||
private void initFromFile(File configFile) {
|
||||
private boolean initFromFile(File configFile) {
|
||||
if (!configFile.exists()) {
|
||||
// Display configuration files aren't required to exist.
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!configFile.isFile()) {
|
||||
Slog.e(TAG, "Display configuration is not a file: " + configFile + ", skipping");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) {
|
||||
@@ -385,6 +388,8 @@ public class DisplayDeviceConfig {
|
||||
Slog.e(TAG, "Encountered an error while reading/parsing display config file: "
|
||||
+ configFile, e);
|
||||
}
|
||||
mLoadedFrom = configFile.toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void initFromGlobalXml() {
|
||||
@@ -395,10 +400,12 @@ public class DisplayDeviceConfig {
|
||||
loadBrightnessRampsFromConfigXml();
|
||||
loadAmbientLightSensorFromConfigXml();
|
||||
setProxSensorUnspecified();
|
||||
mLoadedFrom = "<config.xml>";
|
||||
}
|
||||
|
||||
private void initFromDefaultValues() {
|
||||
// Set all to basic values
|
||||
mLoadedFrom = "Static values";
|
||||
mBacklightMinimum = PowerManager.BRIGHTNESS_MIN;
|
||||
mBacklightMaximum = PowerManager.BRIGHTNESS_MAX;
|
||||
mBrightnessDefault = BRIGHTNESS_DEFAULT;
|
||||
@@ -689,6 +696,11 @@ public class DisplayDeviceConfig {
|
||||
if (sensorDetails != null) {
|
||||
mAmbientLightSensor.type = sensorDetails.getType();
|
||||
mAmbientLightSensor.name = sensorDetails.getName();
|
||||
final RefreshRateRange rr = sensorDetails.getRefreshRate();
|
||||
if (rr != null) {
|
||||
mAmbientLightSensor.minRefreshRate = rr.getMinimum().floatValue();
|
||||
mAmbientLightSensor.maxRefreshRate = rr.getMaximum().floatValue();
|
||||
}
|
||||
} else {
|
||||
loadAmbientLightSensorFromConfigXml();
|
||||
}
|
||||
@@ -704,22 +716,42 @@ public class DisplayDeviceConfig {
|
||||
if (sensorDetails != null) {
|
||||
mProximitySensor.name = sensorDetails.getName();
|
||||
mProximitySensor.type = sensorDetails.getType();
|
||||
final RefreshRateRange rr = sensorDetails.getRefreshRate();
|
||||
if (rr != null) {
|
||||
mProximitySensor.minRefreshRate = rr.getMinimum().floatValue();
|
||||
mProximitySensor.maxRefreshRate = rr.getMaximum().floatValue();
|
||||
}
|
||||
} else {
|
||||
setProxSensorUnspecified();
|
||||
}
|
||||
}
|
||||
|
||||
static class SensorIdentifier {
|
||||
static class SensorData {
|
||||
public String type;
|
||||
public String name;
|
||||
public float minRefreshRate = 0.0f;
|
||||
public float maxRefreshRate = Float.POSITIVE_INFINITY;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Sensor{"
|
||||
+ "type: \"" + type + "\""
|
||||
+ ", name: \"" + name + "\""
|
||||
+ "type: " + type
|
||||
+ ", name: " + name
|
||||
+ ", refreshRateRange: [" + minRefreshRate + ", " + maxRefreshRate + "]"
|
||||
+ "} ";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the sensor matches both the specified name and type, or one if only
|
||||
* one is specified (not-empty). Always returns false if both parameters are null or empty.
|
||||
*/
|
||||
public boolean matches(String sensorName, String sensorType) {
|
||||
final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
|
||||
final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
|
||||
return (isNameSpecified || isTypeSpecified)
|
||||
&& (!isNameSpecified || sensorName.equals(name))
|
||||
&& (!isTypeSpecified || sensorType.equals(type));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -50,6 +50,7 @@ import android.content.res.TypedArray;
|
||||
import android.database.ContentObserver;
|
||||
import android.graphics.ColorSpace;
|
||||
import android.graphics.Point;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.devicestate.DeviceStateManager;
|
||||
import android.hardware.display.AmbientBrightnessDayStats;
|
||||
@@ -62,6 +63,7 @@ import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.DisplayGroupListener;
|
||||
import android.hardware.display.DisplayManagerInternal.DisplayTransactionListener;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||
import android.hardware.display.DisplayViewport;
|
||||
import android.hardware.display.DisplayedContentSample;
|
||||
import android.hardware.display.DisplayedContentSamplingAttributes;
|
||||
@@ -119,6 +121,8 @@ import com.android.server.DisplayThread;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.UiThread;
|
||||
import com.android.server.display.DisplayDeviceConfig.SensorData;
|
||||
import com.android.server.display.utils.SensorUtils;
|
||||
import com.android.server.wm.SurfaceAnimationThread;
|
||||
import com.android.server.wm.WindowManagerInternal;
|
||||
|
||||
@@ -3257,6 +3261,40 @@ public final class DisplayManagerService extends SystemService {
|
||||
public int getRefreshRateSwitchingType() {
|
||||
return getRefreshRateSwitchingTypeInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RefreshRateRange getRefreshRateForDisplayAndSensor(int displayId, String sensorName,
|
||||
String sensorType) {
|
||||
final SensorManager sensorManager;
|
||||
synchronized (mSyncRoot) {
|
||||
sensorManager = mSensorManager;
|
||||
}
|
||||
if (sensorManager == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify that the specified sensor exists.
|
||||
final Sensor sensor = SensorUtils.findSensor(sensorManager, sensorType, sensorName,
|
||||
SensorUtils.NO_FALLBACK);
|
||||
if (sensor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
synchronized (mSyncRoot) {
|
||||
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
|
||||
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
|
||||
if (device == null) {
|
||||
return null;
|
||||
}
|
||||
final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
|
||||
SensorData sensorData = config.getProximitySensor();
|
||||
if (sensorData.matches(sensorName, sensorType)) {
|
||||
return new RefreshRateRange(sensorData.minRefreshRate,
|
||||
sensorData.maxRefreshRate);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class DesiredDisplayModeSpecsObserver
|
||||
|
||||
@@ -27,6 +27,8 @@ import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||
import android.hardware.fingerprint.IUdfpsHbmListener;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
@@ -51,6 +53,8 @@ import com.android.internal.os.BackgroundThread;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.display.utils.AmbientFilter;
|
||||
import com.android.server.display.utils.AmbientFilterFactory;
|
||||
import com.android.server.sensors.SensorManagerInternal;
|
||||
import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
import com.android.server.utils.DeviceConfigInterface;
|
||||
|
||||
@@ -85,8 +89,7 @@ public class DisplayModeDirector {
|
||||
|
||||
private static final int INVALID_DISPLAY_MODE_ID = -1;
|
||||
|
||||
// The tolerance within which we consider something approximately equals.
|
||||
private static final float FLOAT_TOLERANCE = 0.01f;
|
||||
private static final float FLOAT_TOLERANCE = RefreshRateRange.FLOAT_TOLERANCE;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private final Context mContext;
|
||||
@@ -98,6 +101,7 @@ public class DisplayModeDirector {
|
||||
private final SettingsObserver mSettingsObserver;
|
||||
private final DisplayObserver mDisplayObserver;
|
||||
private final UdfpsObserver mUdfpsObserver;
|
||||
private final SensorObserver mSensorObserver;
|
||||
private final DeviceConfigInterface mDeviceConfig;
|
||||
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
|
||||
|
||||
@@ -139,6 +143,11 @@ public class DisplayModeDirector {
|
||||
mDisplayObserver = new DisplayObserver(context, handler);
|
||||
mBrightnessObserver = new BrightnessObserver(context, handler);
|
||||
mUdfpsObserver = new UdfpsObserver();
|
||||
mSensorObserver = new SensorObserver(context, (displayId, priority, vote) -> {
|
||||
synchronized (mLock) {
|
||||
updateVoteLocked(displayId, priority, vote);
|
||||
}
|
||||
});
|
||||
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
|
||||
mDeviceConfig = injector.getDeviceConfig();
|
||||
mAlwaysRespectAppRequest = false;
|
||||
@@ -155,6 +164,7 @@ public class DisplayModeDirector {
|
||||
mSettingsObserver.observe();
|
||||
mDisplayObserver.observe();
|
||||
mBrightnessObserver.observe(sensorManager);
|
||||
mSensorObserver.observe();
|
||||
synchronized (mLock) {
|
||||
// We may have a listener already registered before the call to start, so go ahead and
|
||||
// notify them to pick up our newly initialized state.
|
||||
@@ -585,6 +595,7 @@ public class DisplayModeDirector {
|
||||
mAppRequestObserver.dumpLocked(pw);
|
||||
mBrightnessObserver.dumpLocked(pw);
|
||||
mUdfpsObserver.dumpLocked(pw);
|
||||
mSensorObserver.dumpLocked(pw);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,66 +778,6 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about the min and max refresh rate DM would like to set the display to.
|
||||
*/
|
||||
public static final class RefreshRateRange {
|
||||
/**
|
||||
* The lowest desired refresh rate.
|
||||
*/
|
||||
public float min;
|
||||
/**
|
||||
* The highest desired refresh rate.
|
||||
*/
|
||||
public float max;
|
||||
|
||||
public RefreshRateRange() {}
|
||||
|
||||
public RefreshRateRange(float min, float max) {
|
||||
if (min < 0 || max < 0 || min > max + FLOAT_TOLERANCE) {
|
||||
Slog.e(TAG, "Wrong values for min and max when initializing RefreshRateRange : "
|
||||
+ min + " " + max);
|
||||
this.min = this.max = 0;
|
||||
return;
|
||||
}
|
||||
if (min > max) {
|
||||
// Min and max are within epsilon of each other, but in the wrong order.
|
||||
float t = min;
|
||||
min = max;
|
||||
max = t;
|
||||
}
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the two objects have the same values.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(other instanceof RefreshRateRange)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefreshRateRange refreshRateRange = (RefreshRateRange) other;
|
||||
return (min == refreshRateRange.min && max == refreshRateRange.max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(min, max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "(" + min + " " + max + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about the desired display mode to be set by the system. Includes the base
|
||||
* mode ID and the primary and app request refresh rate ranges.
|
||||
@@ -987,9 +938,13 @@ public class DisplayModeDirector {
|
||||
// user seeing the display flickering when the switches occur.
|
||||
public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
|
||||
|
||||
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
|
||||
// set to a high priority.
|
||||
public static final int PRIORITY_PROXIMITY = 9;
|
||||
|
||||
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
|
||||
// to function, so this needs to be the highest priority of all votes.
|
||||
public static final int PRIORITY_UDFPS = 9;
|
||||
public static final int PRIORITY_UDFPS = 10;
|
||||
|
||||
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
|
||||
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
|
||||
@@ -1086,6 +1041,8 @@ public class DisplayModeDirector {
|
||||
return "PRIORITY_LOW_POWER_MODE";
|
||||
case PRIORITY_UDFPS:
|
||||
return "PRIORITY_UDFPS";
|
||||
case PRIORITY_PROXIMITY:
|
||||
return "PRIORITY_PROXIMITY";
|
||||
|
||||
default:
|
||||
return Integer.toString(priority);
|
||||
@@ -2142,6 +2099,62 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
private static class SensorObserver implements ProximityActiveListener {
|
||||
private static final String PROXIMITY_SENSOR_NAME = null;
|
||||
private static final String PROXIMITY_SENSOR_TYPE = Sensor.STRING_TYPE_PROXIMITY;
|
||||
|
||||
private final BallotBox mBallotBox;
|
||||
private final Context mContext;
|
||||
|
||||
private DisplayManager mDisplayManager;
|
||||
private DisplayManagerInternal mDisplayManagerInternal;
|
||||
private boolean mIsProxActive = false;
|
||||
|
||||
SensorObserver(Context context, BallotBox ballotBox) {
|
||||
mContext = context;
|
||||
mBallotBox = ballotBox;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProximityActive(boolean isActive) {
|
||||
if (mIsProxActive != isActive) {
|
||||
mIsProxActive = isActive;
|
||||
recalculateVotes();
|
||||
}
|
||||
}
|
||||
|
||||
public void observe() {
|
||||
mDisplayManager = mContext.getSystemService(DisplayManager.class);
|
||||
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
|
||||
|
||||
final SensorManagerInternal sensorManager =
|
||||
LocalServices.getService(SensorManagerInternal.class);
|
||||
sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
|
||||
}
|
||||
|
||||
private void recalculateVotes() {
|
||||
final Display[] displays = mDisplayManager.getDisplays();
|
||||
for (Display d : displays) {
|
||||
int displayId = d.getDisplayId();
|
||||
Vote vote = null;
|
||||
if (mIsProxActive) {
|
||||
final RefreshRateRange rate =
|
||||
mDisplayManagerInternal.getRefreshRateForDisplayAndSensor(
|
||||
displayId, PROXIMITY_SENSOR_NAME, PROXIMITY_SENSOR_TYPE);
|
||||
if (rate != null) {
|
||||
vote = Vote.forRefreshRates(rate.min, rate.max);
|
||||
}
|
||||
}
|
||||
mBallotBox.vote(displayId, Vote.PRIORITY_PROXIMITY, vote);
|
||||
}
|
||||
}
|
||||
|
||||
void dumpLocked(PrintWriter pw) {
|
||||
pw.println(" SensorObserver");
|
||||
pw.println(" mIsProxActive=" + mIsProxActive);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
|
||||
public DeviceConfigDisplaySettings() {
|
||||
}
|
||||
@@ -2328,4 +2341,7 @@ public class DisplayModeDirector {
|
||||
}
|
||||
}
|
||||
|
||||
interface BallotBox {
|
||||
void vote(int displayId, int priority, Vote vote);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ import android.os.SystemProperties;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.MathUtils;
|
||||
import android.util.Slog;
|
||||
@@ -65,13 +64,13 @@ import com.android.server.am.BatteryStatsService;
|
||||
import com.android.server.display.RampAnimator.DualRampAnimator;
|
||||
import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
|
||||
import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
|
||||
import com.android.server.display.utils.SensorUtils;
|
||||
import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
|
||||
import com.android.server.display.whitebalance.DisplayWhiteBalanceFactory;
|
||||
import com.android.server.display.whitebalance.DisplayWhiteBalanceSettings;
|
||||
import com.android.server.policy.WindowManagerPolicy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Controls the power state of the display.
|
||||
@@ -586,26 +585,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
mBrightnessMapper.recalculateSplines(mCdsi.isReduceBrightColorsActivated(), adjustedNits);
|
||||
}
|
||||
|
||||
private Sensor findSensor(String sensorType, String sensorName, int fallbackType,
|
||||
boolean useFallback) {
|
||||
final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
|
||||
final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
|
||||
List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
|
||||
if (isNameSpecified || isTypeSpecified) {
|
||||
for (Sensor sensor : sensors) {
|
||||
if ((!isNameSpecified || sensorName.equals(sensor.getName()))
|
||||
&& (!isTypeSpecified || sensorType.equals(sensor.getStringType()))) {
|
||||
return sensor;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (useFallback) {
|
||||
return mSensorManager.getDefaultSensor(fallbackType);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the proximity sensor screen-off function is available.
|
||||
*/
|
||||
@@ -1654,24 +1633,23 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
|
||||
}
|
||||
|
||||
private void loadAmbientLightSensor() {
|
||||
DisplayDeviceConfig.SensorIdentifier lightSensor =
|
||||
mDisplayDeviceConfig.getAmbientLightSensor();
|
||||
String lightSensorName = lightSensor.name;
|
||||
String lightSensorType = lightSensor.type;
|
||||
mLightSensor = findSensor(lightSensorType, lightSensorName, Sensor.TYPE_LIGHT,
|
||||
mDisplayId == Display.DEFAULT_DISPLAY);
|
||||
DisplayDeviceConfig.SensorData lightSensor = mDisplayDeviceConfig.getAmbientLightSensor();
|
||||
final int fallbackType = mDisplayId == Display.DEFAULT_DISPLAY
|
||||
? Sensor.TYPE_LIGHT : SensorUtils.NO_FALLBACK;
|
||||
mLightSensor = SensorUtils.findSensor(mSensorManager, lightSensor.type, lightSensor.name,
|
||||
fallbackType);
|
||||
}
|
||||
|
||||
private void loadProximitySensor() {
|
||||
if (DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
|
||||
return;
|
||||
}
|
||||
final DisplayDeviceConfig.SensorIdentifier proxSensor =
|
||||
final DisplayDeviceConfig.SensorData proxSensor =
|
||||
mDisplayDeviceConfig.getProximitySensor();
|
||||
final String proxSensorName = proxSensor.name;
|
||||
final String proxSensorType = proxSensor.type;
|
||||
mProximitySensor = findSensor(proxSensorType, proxSensorName, Sensor.TYPE_PROXIMITY,
|
||||
mDisplayId == Display.DEFAULT_DISPLAY);
|
||||
final int fallbackType = mDisplayId == Display.DEFAULT_DISPLAY
|
||||
? Sensor.TYPE_PROXIMITY : SensorUtils.NO_FALLBACK;
|
||||
mProximitySensor = SensorUtils.findSensor(mSensorManager, proxSensor.type, proxSensor.name,
|
||||
fallbackType);
|
||||
if (mProximitySensor != null) {
|
||||
mProximityThreshold = Math.min(mProximitySensor.getMaximumRange(),
|
||||
TYPICAL_PROXIMITY_THRESHOLD);
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.server.display.utils;
|
||||
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides utility methods for dealing with sensors.
|
||||
*/
|
||||
public class SensorUtils {
|
||||
public static final int NO_FALLBACK = 0;
|
||||
|
||||
/**
|
||||
* Finds the specified sensor by type and name using SensorManager.
|
||||
*/
|
||||
public static Sensor findSensor(SensorManager sensorManager, String sensorType,
|
||||
String sensorName, int fallbackType) {
|
||||
final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
|
||||
final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
|
||||
if (isNameSpecified || isTypeSpecified) {
|
||||
final List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
|
||||
for (Sensor sensor : sensors) {
|
||||
if ((!isNameSpecified || sensorName.equals(sensor.getName()))
|
||||
&& (!isTypeSpecified || sensorType.equals(sensor.getStringType()))) {
|
||||
return sensor;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fallbackType != NO_FALLBACK) {
|
||||
return sensorManager.getDefaultSensor(fallbackType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
namespace android {
|
||||
|
||||
static JavaVM* sJvm = nullptr;
|
||||
static jmethodID sMethodIdOnProximityActive;
|
||||
|
||||
class NativeSensorService {
|
||||
@@ -93,8 +94,8 @@ NativeSensorService::ProximityActiveListenerDelegate::~ProximityActiveListenerDe
|
||||
}
|
||||
|
||||
void NativeSensorService::ProximityActiveListenerDelegate::onProximityActive(bool isActive) {
|
||||
AndroidRuntime::getJNIEnv()->CallVoidMethod(mListener, sMethodIdOnProximityActive,
|
||||
static_cast<jboolean>(isActive));
|
||||
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
|
||||
jniEnv->CallVoidMethod(mListener, sMethodIdOnProximityActive, static_cast<jboolean>(isActive));
|
||||
}
|
||||
|
||||
static jlong startSensorServiceNative(JNIEnv* env, jclass, jobject listener) {
|
||||
@@ -128,7 +129,8 @@ static const JNINativeMethod methods[] = {
|
||||
|
||||
};
|
||||
|
||||
int register_android_server_sensor_SensorService(JNIEnv* env) {
|
||||
int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env) {
|
||||
sJvm = vm;
|
||||
jclass listenerClass = FindClassOrDie(env, PROXIMITY_ACTIVE_CLASS);
|
||||
sMethodIdOnProximityActive = GetMethodIDOrDie(env, listenerClass, "onProximityActive", "(Z)V");
|
||||
return jniRegisterNativeMethods(env, "com/android/server/sensors/SensorService", methods,
|
||||
|
||||
@@ -62,7 +62,7 @@ int register_android_server_AdbDebuggingManager(JNIEnv* env);
|
||||
int register_android_server_FaceService(JNIEnv* env);
|
||||
int register_android_server_GpuService(JNIEnv* env);
|
||||
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
|
||||
int register_android_server_sensor_SensorService(JNIEnv* env);
|
||||
int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env);
|
||||
};
|
||||
|
||||
using namespace android;
|
||||
@@ -118,6 +118,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
|
||||
register_android_server_FaceService(env);
|
||||
register_android_server_GpuService(env);
|
||||
register_android_server_stats_pull_StatsPullAtomService(env);
|
||||
register_android_server_sensor_SensorService(env);
|
||||
register_android_server_sensor_SensorService(vm, env);
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
@@ -129,14 +129,30 @@
|
||||
<xs:complexType name="sensorDetails">
|
||||
<xs:sequence>
|
||||
<xs:element type="xs:string" name="type" minOccurs="0" maxOccurs="1">
|
||||
<xs:annotation name="nullable" />
|
||||
<xs:annotation name="nullable"/>
|
||||
<xs:annotation name="final"/>
|
||||
</xs:element>
|
||||
<xs:element type="xs:string" name="name" minOccurs="0" maxOccurs="1">
|
||||
<xs:annotation name="nullable" />
|
||||
<xs:annotation name="nullable"/>
|
||||
<xs:annotation name="final"/>
|
||||
</xs:element>
|
||||
<xs:element type="refreshRateRange" name="refreshRate" minOccurs="0" maxOccurs="1">
|
||||
<xs:annotation name="nullable"/>
|
||||
<xs:annotation name="final"/>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="refreshRateRange">
|
||||
<xs:sequence>
|
||||
<xs:element type="xs:nonNegativeInteger" name="minimum" minOccurs="1" maxOccurs="1">
|
||||
<xs:annotation name="final"/>
|
||||
</xs:element>
|
||||
<xs:element type="xs:nonNegativeInteger" name="maximum" minOccurs="1" maxOccurs="1">
|
||||
<xs:annotation name="final"/>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
|
||||
</xs:schema>
|
||||
|
||||
@@ -65,11 +65,21 @@ package com.android.server.display.config {
|
||||
method public final void setValue(@NonNull java.math.BigDecimal);
|
||||
}
|
||||
|
||||
public class RefreshRateRange {
|
||||
ctor public RefreshRateRange();
|
||||
method public final java.math.BigInteger getMaximum();
|
||||
method public final java.math.BigInteger getMinimum();
|
||||
method public final void setMaximum(java.math.BigInteger);
|
||||
method public final void setMinimum(java.math.BigInteger);
|
||||
}
|
||||
|
||||
public class SensorDetails {
|
||||
ctor public SensorDetails();
|
||||
method @Nullable public final String getName();
|
||||
method @Nullable public final com.android.server.display.config.RefreshRateRange getRefreshRate();
|
||||
method @Nullable public final String getType();
|
||||
method public final void setName(@Nullable String);
|
||||
method public final void setRefreshRate(@Nullable com.android.server.display.config.RefreshRateRange);
|
||||
method public final void setType(@Nullable String);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.when;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
@@ -589,8 +590,8 @@ public class LocalDisplayAdapterTest {
|
||||
new DisplayModeDirector.DesiredDisplayModeSpecs(
|
||||
/*baseModeId*/ baseModeId,
|
||||
/*allowGroupSwitching*/ false,
|
||||
new DisplayModeDirector.RefreshRateRange(60f, 60f),
|
||||
new DisplayModeDirector.RefreshRateRange(60f, 60f)
|
||||
new RefreshRateRange(60f, 60f),
|
||||
new RefreshRateRange(60f, 60f)
|
||||
));
|
||||
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
|
||||
verify(mSurfaceControlProxy).setDesiredDisplayModeSpecs(display.token,
|
||||
@@ -624,8 +625,8 @@ public class LocalDisplayAdapterTest {
|
||||
new DisplayModeDirector.DesiredDisplayModeSpecs(
|
||||
/*baseModeId*/ baseModeId,
|
||||
/*allowGroupSwitching*/ false,
|
||||
new DisplayModeDirector.RefreshRateRange(60f, 60f),
|
||||
new DisplayModeDirector.RefreshRateRange(60f, 60f)
|
||||
new RefreshRateRange(60f, 60f),
|
||||
new RefreshRateRange(60f, 60f)
|
||||
));
|
||||
|
||||
waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
|
||||
|
||||
@@ -64,6 +64,7 @@ import com.android.server.LocalServices;
|
||||
import com.android.server.SystemService;
|
||||
import com.android.server.display.DisplayManagerService.SyncRoot;
|
||||
import com.android.server.lights.LightsManager;
|
||||
import com.android.server.sensors.SensorManagerInternal;
|
||||
import com.android.server.wm.WindowManagerInternal;
|
||||
|
||||
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
|
||||
@@ -150,6 +151,7 @@ public class DisplayManagerServiceTest {
|
||||
@Mock LightsManager mMockLightsManager;
|
||||
@Mock VirtualDisplayAdapter mMockVirtualDisplayAdapter;
|
||||
@Mock IBinder mMockDisplayToken;
|
||||
@Mock SensorManagerInternal mMockSensorManagerInternal;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -161,6 +163,8 @@ public class DisplayManagerServiceTest {
|
||||
LocalServices.addService(WindowManagerInternal.class, mMockWindowManagerInternal);
|
||||
LocalServices.removeServiceForTest(LightsManager.class);
|
||||
LocalServices.addService(LightsManager.class, mMockLightsManager);
|
||||
LocalServices.removeServiceForTest(SensorManagerInternal.class);
|
||||
LocalServices.addService(SensorManagerInternal.class, mMockSensorManagerInternal);
|
||||
|
||||
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ import android.hardware.Sensor;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
|
||||
import android.hardware.fingerprint.IUdfpsHbmListener;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
@@ -70,6 +72,8 @@ import com.android.server.LocalServices;
|
||||
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.sensors.SensorManagerInternal;
|
||||
import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;
|
||||
import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
import com.android.server.testutils.FakeDeviceConfigInterface;
|
||||
|
||||
@@ -105,6 +109,10 @@ public class DisplayModeDirectorTest {
|
||||
public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule();
|
||||
@Mock
|
||||
public StatusBarManagerInternal mStatusBarMock;
|
||||
@Mock
|
||||
public SensorManagerInternal mSensorManagerInternalMock;
|
||||
@Mock
|
||||
public DisplayManagerInternal mDisplayManagerInternalMock;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -117,6 +125,10 @@ public class DisplayModeDirectorTest {
|
||||
|
||||
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
|
||||
LocalServices.addService(StatusBarManagerInternal.class, mStatusBarMock);
|
||||
LocalServices.removeServiceForTest(SensorManagerInternal.class);
|
||||
LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
|
||||
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
|
||||
LocalServices.addService(DisplayManagerInternal.class, mDisplayManagerInternalMock);
|
||||
}
|
||||
|
||||
private DisplayModeDirector createDirectorFromRefreshRateArray(
|
||||
@@ -1214,10 +1226,39 @@ public class DisplayModeDirectorTest {
|
||||
assertThat(desiredSpecs.baseModeId).isEqualTo(8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProximitySensorVoting() throws Exception {
|
||||
DisplayModeDirector director =
|
||||
createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
|
||||
director.start(createMockSensorManager());
|
||||
|
||||
ArgumentCaptor<ProximityActiveListener> captor =
|
||||
ArgumentCaptor.forClass(ProximityActiveListener.class);
|
||||
verify(mSensorManagerInternalMock).addProximityActiveListener(any(Executor.class),
|
||||
captor.capture());
|
||||
ProximityActiveListener listener = captor.getValue();
|
||||
|
||||
// Verify that there is no proximity vote initially
|
||||
Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
|
||||
assertNull(vote);
|
||||
|
||||
when(mDisplayManagerInternalMock.getRefreshRateForDisplayAndSensor(eq(DISPLAY_ID), eq(null),
|
||||
eq(Sensor.STRING_TYPE_PROXIMITY))).thenReturn(new RefreshRateRange(60, 60));
|
||||
|
||||
// Set the proximity to active and verify that we added a vote.
|
||||
listener.onProximityActive(true);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
|
||||
assertVoteForRefreshRate(vote, 60.f);
|
||||
|
||||
// Turn prox off and verify vote is gone.
|
||||
listener.onProximityActive(false);
|
||||
vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
|
||||
assertNull(vote);
|
||||
}
|
||||
|
||||
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
|
||||
assertThat(vote).isNotNull();
|
||||
final DisplayModeDirector.RefreshRateRange expectedRange =
|
||||
new DisplayModeDirector.RefreshRateRange(refreshRate, refreshRate);
|
||||
final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
|
||||
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user