Loading services/core/java/com/android/server/display/DisplayDeviceConfig.java +3 −0 Original line number Diff line number Diff line Loading @@ -2630,6 +2630,9 @@ public class DisplayDeviceConfig { } } /** * Uniquely identifies a Sensor, with the combination of Type and Name. */ static class SensorData { public String type; public String name; Loading services/core/java/com/android/server/display/DisplayModeDirector.java +74 −43 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfigInterface; import android.provider.Settings; import android.sysprop.SurfaceFlingerProperties; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.Pair; import android.util.Slog; Loading @@ -70,6 +69,7 @@ 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.display.utils.SensorUtils; import com.android.server.sensors.SensorManagerInternal; import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener; import com.android.server.statusbar.StatusBarManagerInternal; Loading Loading @@ -683,14 +683,20 @@ public class DisplayModeDirector { } /** * 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); } /** Loading Loading @@ -1739,6 +1745,9 @@ public class DisplayModeDirector { 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 Loading Loading @@ -1899,17 +1908,8 @@ public class DisplayModeDirector { 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. Loading Loading @@ -2053,6 +2053,10 @@ public class DisplayModeDirector { pw.println(" mAmbientHighBrightnessThresholds: " + d); } pw.println(" mRegisteredLightSensor: " + mRegisteredLightSensor); pw.println(" mLightSensor: " + mLightSensor); pw.println(" mLightSensorName: " + mLightSensorName); pw.println(" mLightSensorType: " + mLightSensorType); mLightSensorListener.dumpLocked(pw); if (mAmbientFilter != null) { Loading Loading @@ -2106,27 +2110,9 @@ public class DisplayModeDirector { } 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); Loading @@ -2137,14 +2123,40 @@ public class DisplayModeDirector { mLightSensor = null; } if (mRefreshRateChangeable) { updateSensorStatus(); if (mRefreshRateChangeable) { 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. Loading Loading @@ -2288,19 +2300,38 @@ public class DisplayModeDirector { if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) { registerLightSensor(); } else { 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"); } } else { } private void unregisterSensorListener() { mLightSensorListener.removeCallbacks(); mSensorManager.unregisterListener(mLightSensorListener); mRegisteredLightSensor = null; if (mLoggingEnabled) { Slog.d(TAG, "updateSensorStatus: unregisterListener"); } } } private boolean isDeviceActive() { return mDefaultDisplayState == Display.STATE_ON; Loading services/core/java/com/android/server/display/utils/SensorUtils.java +4 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,10 @@ public class SensorUtils { */ public static Sensor findSensor(SensorManager sensorManager, String sensorType, String sensorName, int fallbackType) { if (sensorManager == null) { return null; } if ("".equals(sensorName) && "".equals(sensorType)) { return null; } Loading services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +58 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ 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.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; Loading Loading @@ -73,6 +74,7 @@ import android.provider.Settings; import android.test.mock.MockContentResolver; import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.view.Display; import android.view.SurfaceControl.RefreshRateRange; import android.view.SurfaceControl.RefreshRateRanges; Loading Loading @@ -102,6 +104,7 @@ import org.mockito.ArgumentCaptor; 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; Loading Loading @@ -2293,6 +2296,61 @@ public class DisplayModeDirectorTest { 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); } Loading Loading
services/core/java/com/android/server/display/DisplayDeviceConfig.java +3 −0 Original line number Diff line number Diff line Loading @@ -2630,6 +2630,9 @@ public class DisplayDeviceConfig { } } /** * Uniquely identifies a Sensor, with the combination of Type and Name. */ static class SensorData { public String type; public String name; Loading
services/core/java/com/android/server/display/DisplayModeDirector.java +74 −43 Original line number Diff line number Diff line Loading @@ -50,7 +50,6 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfigInterface; import android.provider.Settings; import android.sysprop.SurfaceFlingerProperties; import android.text.TextUtils; import android.util.IndentingPrintWriter; import android.util.Pair; import android.util.Slog; Loading @@ -70,6 +69,7 @@ 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.display.utils.SensorUtils; import com.android.server.sensors.SensorManagerInternal; import com.android.server.sensors.SensorManagerInternal.ProximityActiveListener; import com.android.server.statusbar.StatusBarManagerInternal; Loading Loading @@ -683,14 +683,20 @@ public class DisplayModeDirector { } /** * 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); } /** Loading Loading @@ -1739,6 +1745,9 @@ public class DisplayModeDirector { 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 Loading Loading @@ -1899,17 +1908,8 @@ public class DisplayModeDirector { 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. Loading Loading @@ -2053,6 +2053,10 @@ public class DisplayModeDirector { pw.println(" mAmbientHighBrightnessThresholds: " + d); } pw.println(" mRegisteredLightSensor: " + mRegisteredLightSensor); pw.println(" mLightSensor: " + mLightSensor); pw.println(" mLightSensorName: " + mLightSensorName); pw.println(" mLightSensorType: " + mLightSensorType); mLightSensorListener.dumpLocked(pw); if (mAmbientFilter != null) { Loading Loading @@ -2106,27 +2110,9 @@ public class DisplayModeDirector { } 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); Loading @@ -2137,14 +2123,40 @@ public class DisplayModeDirector { mLightSensor = null; } if (mRefreshRateChangeable) { updateSensorStatus(); if (mRefreshRateChangeable) { 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. Loading Loading @@ -2288,19 +2300,38 @@ public class DisplayModeDirector { if ((mShouldObserveAmbientLowChange || mShouldObserveAmbientHighChange) && isDeviceActive() && !mLowPowerModeEnabled && mRefreshRateChangeable) { registerLightSensor(); } else { 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"); } } else { } private void unregisterSensorListener() { mLightSensorListener.removeCallbacks(); mSensorManager.unregisterListener(mLightSensorListener); mRegisteredLightSensor = null; if (mLoggingEnabled) { Slog.d(TAG, "updateSensorStatus: unregisterListener"); } } } private boolean isDeviceActive() { return mDefaultDisplayState == Display.STATE_ON; Loading
services/core/java/com/android/server/display/utils/SensorUtils.java +4 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,10 @@ public class SensorUtils { */ public static Sensor findSensor(SensorManager sensorManager, String sensorType, String sensorName, int fallbackType) { if (sensorManager == null) { return null; } if ("".equals(sensorName) && "".equals(sensorType)) { return null; } Loading
services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java +58 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ 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.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; Loading Loading @@ -73,6 +74,7 @@ import android.provider.Settings; import android.test.mock.MockContentResolver; import android.util.Slog; import android.util.SparseArray; import android.util.TypedValue; import android.view.Display; import android.view.SurfaceControl.RefreshRateRange; import android.view.SurfaceControl.RefreshRateRanges; Loading Loading @@ -102,6 +104,7 @@ import org.mockito.ArgumentCaptor; 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; Loading Loading @@ -2293,6 +2296,61 @@ public class DisplayModeDirectorTest { 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); } Loading