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:
Santos Cordon
2021-05-18 13:27:36 +01:00
parent 04350c57de
commit 8a3115ba6e
13 changed files with 401 additions and 123 deletions

View File

@@ -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 + ")";
}
}
}

View File

@@ -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));
}
}
/**

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);
}