Merge "Reload the Ambient Light Sensor on Display Change" into tm-qpr-dev
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 5bdfa70..9278743 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -2644,6 +2644,9 @@
}
}
+ /**
+ * Uniquely identifies a Sensor, with the combination of Type and Name.
+ */
static class SensorData {
public String type;
public String name;
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 6331a5d..aafba5a 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -50,7 +50,6 @@
import android.provider.DeviceConfig;
import android.provider.DeviceConfigInterface;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.Pair;
import android.util.Slog;
@@ -68,6 +67,7 @@
import com.android.server.LocalServices;
import com.android.server.display.utils.AmbientFilter;
import com.android.server.display.utils.AmbientFilterFactory;
+import com.android.server.display.utils.SensorUtils;
import com.android.server.sensors.SensorManagerInternal;
import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -520,14 +520,20 @@
}
/**
- * A utility to make this class aware of the new display configs whenever the default display is
- * changed
+ * Called when the underlying display device of the default display is changed.
+ * Some data in this class relates to the physical display of the device, and so we need to
+ * reload the configurations based on this.
+ * E.g. the brightness sensors and refresh rate capabilities depend on the physical display
+ * device that is being used, so will be reloaded.
+ *
+ * @param displayDeviceConfig configurations relating to the underlying display device.
*/
public void defaultDisplayDeviceUpdated(DisplayDeviceConfig displayDeviceConfig) {
mSettingsObserver.setRefreshRates(displayDeviceConfig,
/* attemptLoadingFromDeviceConfig= */ true);
mBrightnessObserver.updateBlockingZoneThresholds(displayDeviceConfig,
/* attemptLoadingFromDeviceConfig= */ true);
+ mBrightnessObserver.reloadLightSensor(displayDeviceConfig);
}
/**
@@ -1541,6 +1547,9 @@
private SensorManager mSensorManager;
private Sensor mLightSensor;
+ private Sensor mRegisteredLightSensor;
+ private String mLightSensorType;
+ private String mLightSensorName;
private final LightSensorEventListener mLightSensorListener =
new LightSensorEventListener();
// Take it as low brightness before valid sensor data comes
@@ -1701,17 +1710,8 @@
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 = getBrightness(Display.DEFAULT_DISPLAY);
// DeviceConfig is accessible after system ready.
@@ -1855,6 +1855,10 @@
pw.println(" mAmbientHighBrightnessThresholds: " + d);
}
+ pw.println(" mLightSensor: " + mLightSensor);
+ pw.println(" mRegisteredLightSensor: " + mRegisteredLightSensor);
+ pw.println(" mLightSensorName: " + mLightSensorName);
+ pw.println(" mLightSensorType: " + mLightSensorType);
mLightSensorListener.dumpLocked(pw);
if (mAmbientFilter != null) {
@@ -1908,27 +1912,9 @@
}
if (mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) {
- Resources resources = mContext.getResources();
- String lightSensorType = resources.getString(
- com.android.internal.R.string.config_displayLightSensorType);
+ Sensor lightSensor = getLightSensor();
- Sensor lightSensor = null;
- if (!TextUtils.isEmpty(lightSensorType)) {
- List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
- for (int i = 0; i < sensors.size(); i++) {
- Sensor sensor = sensors.get(i);
- if (lightSensorType.equals(sensor.getStringType())) {
- lightSensor = sensor;
- break;
- }
- }
- }
-
- if (lightSensor == null) {
- lightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
- }
-
- if (lightSensor != null) {
+ if (lightSensor != null && lightSensor != mLightSensor) {
final Resources res = mContext.getResources();
mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, res);
@@ -1938,15 +1924,40 @@
mAmbientFilter = null;
mLightSensor = null;
}
-
+ updateSensorStatus();
if (mRefreshRateChangeable) {
- updateSensorStatus();
synchronized (mLock) {
onBrightnessChangedLocked();
}
}
}
+ private void reloadLightSensor(DisplayDeviceConfig displayDeviceConfig) {
+ reloadLightSensorData(displayDeviceConfig);
+ restartObserver();
+ }
+
+ private void reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig) {
+ // The displayDeviceConfig (ddc) contains display specific preferences. When loaded,
+ // it naturally falls back to the global config.xml.
+ if (displayDeviceConfig != null
+ && displayDeviceConfig.getAmbientLightSensor() != null) {
+ // This covers both the ddc and the config.xml fallback
+ mLightSensorType = displayDeviceConfig.getAmbientLightSensor().type;
+ mLightSensorName = displayDeviceConfig.getAmbientLightSensor().name;
+ } else if (mLightSensorName == null && mLightSensorType == null) {
+ Resources resources = mContext.getResources();
+ mLightSensorType = resources.getString(
+ com.android.internal.R.string.config_displayLightSensorType);
+ mLightSensorName = "";
+ }
+ }
+
+ private Sensor getLightSensor() {
+ return SensorUtils.findSensor(mSensorManager, mLightSensorType,
+ mLightSensorName, Sensor.TYPE_LIGHT);
+ }
+
/**
* Checks to see if at least one value is positive, in which case it is necessary to listen
* to value changes.
@@ -2088,17 +2099,36 @@
if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange)
&& isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) {
- mSensorManager.registerListener(mLightSensorListener,
- mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
- if (mLoggingEnabled) {
- Slog.d(TAG, "updateSensorStatus: registerListener");
- }
+ registerLightSensor();
+
} else {
- mLightSensorListener.removeCallbacks();
- mSensorManager.unregisterListener(mLightSensorListener);
- if (mLoggingEnabled) {
- Slog.d(TAG, "updateSensorStatus: unregisterListener");
- }
+ unregisterSensorListener();
+ }
+ }
+
+ private void registerLightSensor() {
+ if (mRegisteredLightSensor == mLightSensor) {
+ return;
+ }
+
+ if (mRegisteredLightSensor != null) {
+ unregisterSensorListener();
+ }
+
+ mSensorManager.registerListener(mLightSensorListener,
+ mLightSensor, LIGHT_SENSOR_RATE_MS * 1000, mHandler);
+ mRegisteredLightSensor = mLightSensor;
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "updateSensorStatus: registerListener");
+ }
+ }
+
+ private void unregisterSensorListener() {
+ mLightSensorListener.removeCallbacks();
+ mSensorManager.unregisterListener(mLightSensorListener);
+ mRegisteredLightSensor = null;
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "updateSensorStatus: unregisterListener");
}
}
diff --git a/services/core/java/com/android/server/display/utils/SensorUtils.java b/services/core/java/com/android/server/display/utils/SensorUtils.java
index 4924ad5..48bc46c 100644
--- a/services/core/java/com/android/server/display/utils/SensorUtils.java
+++ b/services/core/java/com/android/server/display/utils/SensorUtils.java
@@ -33,6 +33,10 @@
*/
public static Sensor findSensor(SensorManager sensorManager, String sensorType,
String sensorName, int fallbackType) {
+ if (sensorManager == null) {
+ return null;
+ }
+
if ("".equals(sensorName) && "".equals(sensorType)) {
return null;
}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index cfea63b..b133a2a 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -40,6 +40,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -74,6 +75,7 @@
import android.test.mock.MockContentResolver;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.TypedValue;
import android.view.Display;
import androidx.test.core.app.ApplicationProvider;
@@ -102,6 +104,7 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1939,6 +1942,61 @@
new int[]{20});
}
+ @Test
+ public void testSensorReloadOnDeviceSwitch() throws Exception {
+ // First, configure brightness zones or DMD won't register for sensor data.
+ final FakeDeviceConfig config = mInjector.getDeviceConfig();
+ config.setRefreshRateInHighZone(60);
+ config.setHighDisplayBrightnessThresholds(new int[] { 255 });
+ config.setHighAmbientBrightnessThresholds(new int[] { 8000 });
+
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ setPeakRefreshRate(90 /*fps*/);
+ director.getSettingsObserver().setDefaultRefreshRate(90);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+
+ Sensor lightSensorOne = TestUtils.createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
+ Sensor lightSensorTwo = TestUtils.createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT);
+ SensorManager sensorManager = createMockSensorManager(lightSensorOne, lightSensorTwo);
+ when(sensorManager.getDefaultSensor(5)).thenReturn(lightSensorOne, lightSensorTwo);
+ director.start(sensorManager);
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(sensorManager, Mockito.timeout(TimeUnit.SECONDS.toMillis(1)))
+ .registerListener(
+ listenerCaptor.capture(),
+ eq(lightSensorOne),
+ anyInt(),
+ any(Handler.class));
+
+ DisplayDeviceConfig ddcMock = mock(DisplayDeviceConfig.class);
+ when(ddcMock.getDefaultLowRefreshRate()).thenReturn(50);
+ when(ddcMock.getDefaultHighRefreshRate()).thenReturn(55);
+ when(ddcMock.getLowDisplayBrightnessThresholds()).thenReturn(new int[]{25});
+ when(ddcMock.getLowAmbientBrightnessThresholds()).thenReturn(new int[]{30});
+ when(ddcMock.getHighDisplayBrightnessThresholds()).thenReturn(new int[]{210});
+ when(ddcMock.getHighAmbientBrightnessThresholds()).thenReturn(new int[]{2100});
+
+ Resources resMock = mock(Resources.class);
+ when(resMock.getInteger(
+ com.android.internal.R.integer.config_displayWhiteBalanceBrightnessFilterHorizon))
+ .thenReturn(3);
+ ArgumentCaptor<TypedValue> valueArgumentCaptor = ArgumentCaptor.forClass(TypedValue.class);
+ doAnswer((Answer<Void>) invocation -> {
+ valueArgumentCaptor.getValue().type = 4;
+ valueArgumentCaptor.getValue().data = 13;
+ return null;
+ }).when(resMock).getValue(anyInt(), valueArgumentCaptor.capture(), eq(true));
+ when(mContext.getResources()).thenReturn(resMock);
+
+ director.defaultDisplayDeviceUpdated(ddcMock);
+
+ verify(sensorManager).unregisterListener(any(SensorEventListener.class));
+ verify(sensorManager).registerListener(any(SensorEventListener.class),
+ eq(lightSensorTwo), anyInt(), any(Handler.class));
+ }
+
private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
}