diff options
4 files changed, 436 insertions, 60 deletions
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 40c879a3c5e7..d4877eb4973d 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -1193,17 +1193,15 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } loadScreenOffBrightnessSensor(); int[] sensorValueToLux = mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux(); - // TODO (b/265793751): Don't instantiate ScreenOffBrightnessSensorController if this is - // a complementary display if (mScreenOffBrightnessSensor != null && sensorValueToLux != null) { - mScreenOffBrightnessSensorController = new ScreenOffBrightnessSensorController( - mSensorManager, - mScreenOffBrightnessSensor, - mHandler, - SystemClock::uptimeMillis, - sensorValueToLux, - mInteractiveModeBrightnessMapper - ); + mScreenOffBrightnessSensorController = + mInjector.getScreenOffBrightnessSensorController( + mSensorManager, + mScreenOffBrightnessSensor, + mHandler, + SystemClock::uptimeMillis, + sensorValueToLux, + mInteractiveModeBrightnessMapper); } } else { mUseSoftwareAutoBrightnessConfig = false; @@ -1395,8 +1393,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call if (mScreenOffBrightnessSensorController != null) { mScreenOffBrightnessSensorController.setLightSensorEnabled(mUseAutoBrightness - && (state == Display.STATE_OFF || (state == Display.STATE_DOZE - && !mAllowAutoBrightnessWhileDozingConfig))); + && mIsEnabled && (state == Display.STATE_OFF || (state == Display.STATE_DOZE + && !mAllowAutoBrightnessWhileDozingConfig)) + && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); } boolean skipRampBecauseOfProximityChangeToNegative = false; @@ -2544,11 +2543,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); - mHandler.post(() -> { + mHandler.postAtTime(() -> { mUseAutoBrightness = screenBrightnessModeSetting == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; updatePowerState(); - }); + }, mClock.uptimeMillis()); } private float getAutoBrightnessAdjustmentSetting() { @@ -3446,6 +3445,23 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold, potentialOldBrightnessRange); } + + ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( + SensorManager sensorManager, + Sensor lightSensor, + Handler handler, + ScreenOffBrightnessSensorController.Clock clock, + int[] sensorValueToLux, + BrightnessMappingStrategy brightnessMapper) { + return new ScreenOffBrightnessSensorController( + sensorManager, + lightSensor, + handler, + clock, + sensorValueToLux, + brightnessMapper + ); + } } static class CachedBrightnessInfo { diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java index 5ea8aaa5e814..a92877796a8a 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController2.java +++ b/services/core/java/com/android/server/display/DisplayPowerController2.java @@ -1030,17 +1030,15 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal loadScreenOffBrightnessSensor(); int[] sensorValueToLux = mDisplayDeviceConfig.getScreenOffBrightnessSensorValueToLux(); - // TODO (b/265793751): Don't instantiate ScreenOffBrightnessSensorController if this is - // a complementary display if (mScreenOffBrightnessSensor != null && sensorValueToLux != null) { - mScreenOffBrightnessSensorController = new ScreenOffBrightnessSensorController( - mSensorManager, - mScreenOffBrightnessSensor, - mHandler, - SystemClock::uptimeMillis, - sensorValueToLux, - mInteractiveModeBrightnessMapper - ); + mScreenOffBrightnessSensorController = + mInjector.getScreenOffBrightnessSensorController( + mSensorManager, + mScreenOffBrightnessSensor, + mHandler, + SystemClock::uptimeMillis, + sensorValueToLux, + mInteractiveModeBrightnessMapper); } } else { mUseSoftwareAutoBrightnessConfig = false; @@ -1189,8 +1187,9 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal if (mScreenOffBrightnessSensorController != null) { mScreenOffBrightnessSensorController.setLightSensorEnabled(mUseAutoBrightness - && (state == Display.STATE_OFF || (state == Display.STATE_DOZE - && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig()))); + && mIsEnabled && (state == Display.STATE_OFF || (state == Display.STATE_DOZE + && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig())) + && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); } // Initialize things the first time the power state is changed. @@ -2150,11 +2149,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL, UserHandle.USER_CURRENT); - mHandler.post(() -> { + mHandler.postAtTime(() -> { mUseAutoBrightness = screenBrightnessModeSetting == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; updatePowerState(); - }); + }, mClock.uptimeMillis()); } private float getAutoBrightnessAdjustmentSetting() { @@ -2924,6 +2923,23 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal darkeningThresholdLevels, minDarkeningThreshold, minBrighteningThreshold, potentialOldBrightnessRange); } + + ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( + SensorManager sensorManager, + Sensor lightSensor, + Handler handler, + ScreenOffBrightnessSensorController.Clock clock, + int[] sensorValueToLux, + BrightnessMappingStrategy brightnessMapper) { + return new ScreenOffBrightnessSensorController( + sensorManager, + lightSensor, + handler, + clock, + sensorValueToLux, + brightnessMapper + ); + } } static class CachedBrightnessInfo { diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java index b9f2059c0799..96b63455598d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java @@ -26,12 +26,15 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; +import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.res.Resources; @@ -44,7 +47,9 @@ import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.SystemProperties; +import android.os.UserHandle; import android.os.test.TestLooper; +import android.provider.Settings; import android.util.FloatProperty; import android.view.Display; import android.view.DisplayInfo; @@ -57,6 +62,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.display.RampAnimator.DualRampAnimator; +import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.color.ColorDisplayService; import com.android.server.display.whitebalance.DisplayWhiteBalanceController; import com.android.server.policy.WindowManagerPolicy; @@ -122,6 +128,7 @@ public final class DisplayPowerController2Test { .spyStatic(SystemProperties.class) .spyStatic(LocalServices.class) .spyStatic(BatteryStatsService.class) + .spyStatic(Settings.System.class) .startMocking(); mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); mClock = new OffsettableClock.Stopped(); @@ -139,8 +146,7 @@ public final class DisplayPowerController2Test { ColorDisplayService.ColorDisplayServiceInternal.class)); doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService); - mProxSensor = setUpProxSensor(); - + setUpSensors(); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); } @@ -169,7 +175,7 @@ public final class DisplayPowerController2Test { advanceTime(1); // two times, one for unfinished business and one for proximity - verify(mHolder.wakelockController).acquireWakelock( + verify(mHolder.wakelockController, times(2)).acquireWakelock( WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); verify(mHolder.wakelockController).acquireWakelock( WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); @@ -177,7 +183,7 @@ public final class DisplayPowerController2Test { mHolder.dpc.stop(); advanceTime(1); // two times, one for unfinished business and one for proximity - verify(mHolder.wakelockController).acquireWakelock( + verify(mHolder.wakelockController, times(2)).acquireWakelock( WakelockController.WAKE_LOCK_UNFINISHED_BUSINESS); verify(mHolder.wakelockController).acquireWakelock( WakelockController.WAKE_LOCK_PROXIMITY_DEBOUNCE); @@ -214,12 +220,13 @@ public final class DisplayPowerController2Test { mTestLooper.dispatchAll(); } - private Sensor setUpProxSensor() throws Exception { - Sensor proxSensor = TestUtils.createSensor( + private void setUpSensors() throws Exception { + mProxSensor = TestUtils.createSensor( Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY); + Sensor screenOffBrightnessSensor = TestUtils.createSensor( + Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL))) - .thenReturn(List.of(proxSensor)); - return proxSensor; + .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor)); } private SensorEventListener getSensorEventListener(Sensor sensor) { @@ -229,14 +236,15 @@ public final class DisplayPowerController2Test { } private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock, - DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock) { + DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock, + boolean isEnabled) { DisplayInfo info = new DisplayInfo(); DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId); when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock); when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info); - when(logicalDisplayMock.isEnabledLocked()).thenReturn(true); + when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); @@ -253,7 +261,14 @@ public final class DisplayPowerController2Test { when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn( new DisplayDeviceConfig.SensorData()); when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn( - new DisplayDeviceConfig.SensorData()); + new DisplayDeviceConfig.SensorData() { + { + type = Sensor.STRING_TYPE_LIGHT; + name = null; + } + }); + when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux()) + .thenReturn(new int[0]); } @Test @@ -466,7 +481,7 @@ public final class DisplayPowerController2Test { DisplayPowerRequest dpr = new DisplayPowerRequest(); mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); - verify(mHolder.displayPowerState).setScreenState(anyInt()); + verify(mHolder.displayPowerState, times(2)).setScreenState(anyInt()); mHolder = createDisplayPowerController(42, UNIQUE_ID); @@ -479,8 +494,145 @@ public final class DisplayPowerController2Test { verify(mHolder.displayPowerState).setScreenState(anyInt()); } + @Test + public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_OFF; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(true); + + // The display turns on and we use the brightness value recommended by + // ScreenOffBrightnessSensorController + clearInvocations(mHolder.screenOffBrightnessSensorController); + float brightness = 0.14f; + when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness()) + .thenReturn(brightness); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .getAutomaticScreenBrightness(); + verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat()); + } + + @Test + public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_DOZE; + when(mResourcesMock.getBoolean( + com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing)) + .thenReturn(true); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(true); + + // The display turns on and we use the brightness value recommended by + // ScreenOffBrightnessSensorController + clearInvocations(mHolder.screenOffBrightnessSensorController); + float brightness = 0.14f; + when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness()) + .thenReturn(brightness); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .getAutomaticScreenBrightness(); + verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat()); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_OFF; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_DisplayIsDisabled() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_DisplayIsOn() { + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_DisplayIsAFollower() { + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_OFF; + + mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, /* leadDisplayId= */ 42); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + private DisplayPowerControllerHolder createDisplayPowerController(int displayId, String uniqueId) { + return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true); + } + + private DisplayPowerControllerHolder createDisplayPowerController(int displayId, + String uniqueId, boolean isEnabled) { final DisplayPowerState displayPowerState = mock(DisplayPowerState.class); final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class); final AutomaticBrightnessController automaticBrightnessController = @@ -489,10 +641,12 @@ public final class DisplayPowerController2Test { final BrightnessMappingStrategy brightnessMappingStrategy = mock(BrightnessMappingStrategy.class); final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class); + final ScreenOffBrightnessSensorController screenOffBrightnessSensorController = + mock(ScreenOffBrightnessSensorController.class); TestInjector injector = new TestInjector(displayPowerState, animator, automaticBrightnessController, wakelockController, brightnessMappingStrategy, - hysteresisLevels); + hysteresisLevels, screenOffBrightnessSensorController); final LogicalDisplay display = mock(LogicalDisplay.class); final DisplayDevice device = mock(DisplayDevice.class); @@ -500,7 +654,7 @@ public final class DisplayPowerController2Test { final BrightnessSetting brightnessSetting = mock(BrightnessSetting.class); final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class); - setUpDisplay(displayId, uniqueId, display, device, config); + setUpDisplay(displayId, uniqueId, display, device, config, isEnabled); final DisplayPowerController2 dpc = new DisplayPowerController2( mContextSpy, injector, mDisplayPowerCallbacksMock, mHandler, @@ -509,7 +663,8 @@ public final class DisplayPowerController2Test { hbmMetadata, /* bootCompleted= */ false); return new DisplayPowerControllerHolder(dpc, displayPowerState, brightnessSetting, animator, - automaticBrightnessController, wakelockController); + automaticBrightnessController, wakelockController, + screenOffBrightnessSensorController, hbmMetadata); } /** @@ -523,18 +678,24 @@ public final class DisplayPowerController2Test { public final DualRampAnimator<DisplayPowerState> animator; public final AutomaticBrightnessController automaticBrightnessController; public final WakelockController wakelockController; + public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController; + public final HighBrightnessModeMetadata hbmMetadata; DisplayPowerControllerHolder(DisplayPowerController2 dpc, DisplayPowerState displayPowerState, BrightnessSetting brightnessSetting, DualRampAnimator<DisplayPowerState> animator, AutomaticBrightnessController automaticBrightnessController, - WakelockController wakelockController) { + WakelockController wakelockController, + ScreenOffBrightnessSensorController screenOffBrightnessSensorController, + HighBrightnessModeMetadata hbmMetadata) { this.dpc = dpc; this.displayPowerState = displayPowerState; this.brightnessSetting = brightnessSetting; this.animator = animator; this.automaticBrightnessController = automaticBrightnessController; this.wakelockController = wakelockController; + this.screenOffBrightnessSensorController = screenOffBrightnessSensorController; + this.hbmMetadata = hbmMetadata; } } @@ -545,18 +706,21 @@ public final class DisplayPowerController2Test { private final WakelockController mWakelockController; private final BrightnessMappingStrategy mBrightnessMappingStrategy; private final HysteresisLevels mHysteresisLevels; + private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController; TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator, AutomaticBrightnessController automaticBrightnessController, WakelockController wakelockController, BrightnessMappingStrategy brightnessMappingStrategy, - HysteresisLevels hysteresisLevels) { + HysteresisLevels hysteresisLevels, + ScreenOffBrightnessSensorController screenOffBrightnessSensorController) { mDisplayPowerState = dps; mAnimator = animator; mAutomaticBrightnessController = automaticBrightnessController; mWakelockController = wakelockController; mBrightnessMappingStrategy = brightnessMappingStrategy; mHysteresisLevels = hysteresisLevels; + mScreenOffBrightnessSensorController = screenOffBrightnessSensorController; } @Override @@ -636,5 +800,13 @@ public final class DisplayPowerController2Test { float minBrighteningThreshold, boolean potentialOldBrightnessRange) { return mHysteresisLevels; } + + @Override + ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( + SensorManager sensorManager, Sensor lightSensor, Handler handler, + ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux, + BrightnessMappingStrategy brightnessMapper) { + return mScreenOffBrightnessSensorController; + } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java index 1e9041c48e44..28319acc5f1b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java @@ -26,12 +26,15 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; +import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.res.Resources; @@ -44,7 +47,9 @@ import android.os.Handler; import android.os.Looper; import android.os.PowerManager; import android.os.SystemProperties; +import android.os.UserHandle; import android.os.test.TestLooper; +import android.provider.Settings; import android.util.FloatProperty; import android.view.Display; import android.view.DisplayInfo; @@ -57,6 +62,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito; import com.android.server.LocalServices; import com.android.server.am.BatteryStatsService; import com.android.server.display.RampAnimator.DualRampAnimator; +import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.color.ColorDisplayService; import com.android.server.display.whitebalance.DisplayWhiteBalanceController; import com.android.server.policy.WindowManagerPolicy; @@ -122,6 +128,7 @@ public final class DisplayPowerControllerTest { .spyStatic(SystemProperties.class) .spyStatic(LocalServices.class) .spyStatic(BatteryStatsService.class) + .spyStatic(Settings.System.class) .startMocking(); mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext())); mClock = new OffsettableClock.Stopped(); @@ -140,8 +147,7 @@ public final class DisplayPowerControllerTest { ColorDisplayService.ColorDisplayServiceInternal.class)); doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService); - mProxSensor = setUpProxSensor(); - + setUpSensors(); mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); } @@ -217,12 +223,13 @@ public final class DisplayPowerControllerTest { mTestLooper.dispatchAll(); } - private Sensor setUpProxSensor() throws Exception { - Sensor proxSensor = TestUtils.createSensor( + private void setUpSensors() throws Exception { + mProxSensor = TestUtils.createSensor( Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY); + Sensor screenOffBrightnessSensor = TestUtils.createSensor( + Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL))) - .thenReturn(List.of(proxSensor)); - return proxSensor; + .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor)); } private SensorEventListener getSensorEventListener(Sensor sensor) { @@ -232,14 +239,15 @@ public final class DisplayPowerControllerTest { } private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock, - DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock) { + DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock, + boolean isEnabled) { DisplayInfo info = new DisplayInfo(); DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId); when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock); when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info); - when(logicalDisplayMock.isEnabledLocked()).thenReturn(true); + when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); @@ -256,7 +264,14 @@ public final class DisplayPowerControllerTest { when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn( new DisplayDeviceConfig.SensorData()); when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn( - new DisplayDeviceConfig.SensorData()); + new DisplayDeviceConfig.SensorData() { + { + type = Sensor.STRING_TYPE_LIGHT; + name = null; + } + }); + when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux()) + .thenReturn(new int[0]); } @Test @@ -470,7 +485,7 @@ public final class DisplayPowerControllerTest { DisplayPowerRequest dpr = new DisplayPowerRequest(); mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); advanceTime(1); - verify(mHolder.displayPowerState).setScreenState(anyInt()); + verify(mHolder.displayPowerState, times(2)).setScreenState(anyInt()); mHolder = createDisplayPowerController(42, UNIQUE_ID); @@ -483,8 +498,145 @@ public final class DisplayPowerControllerTest { verify(mHolder.displayPowerState).setScreenState(anyInt()); } + @Test + public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_OFF; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(true); + + // The display turns on and we use the brightness value recommended by + // ScreenOffBrightnessSensorController + clearInvocations(mHolder.screenOffBrightnessSensorController); + float brightness = 0.14f; + when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness()) + .thenReturn(brightness); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .getAutomaticScreenBrightness(); + verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat()); + } + + @Test + public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_DOZE; + when(mResourcesMock.getBoolean( + com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing)) + .thenReturn(true); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(true); + + // The display turns on and we use the brightness value recommended by + // ScreenOffBrightnessSensorController + clearInvocations(mHolder.screenOffBrightnessSensorController); + float brightness = 0.14f; + when(mHolder.screenOffBrightnessSensorController.getAutomaticScreenBrightness()) + .thenReturn(brightness); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); + when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( + any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); + + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .getAutomaticScreenBrightness(); + verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), anyFloat()); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_OFF; + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_DisplayIsDisabled() { + doAnswer((Answer<Integer>) invocationOnMock -> + Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) + .when(() -> Settings.System.getIntForUser(any(ContentResolver.class), + eq(Settings.System.SCREEN_BRIGHTNESS_MODE), anyInt(), + eq(UserHandle.USER_CURRENT))); + mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ false); + + DisplayPowerRequest dpr = new DisplayPowerRequest(); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_DisplayIsOn() { + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; + + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + + @Test + public void testSetScreenOffBrightnessSensorDisabled_DisplayIsAFollower() { + DisplayPowerRequest dpr = new DisplayPowerRequest(); + dpr.policy = DisplayPowerRequest.POLICY_OFF; + + mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, /* leadDisplayId= */ 42); + mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); + advanceTime(1); // Run updatePowerState + + verify(mHolder.screenOffBrightnessSensorController, atLeastOnce()) + .setLightSensorEnabled(false); + } + private DisplayPowerControllerHolder createDisplayPowerController(int displayId, String uniqueId) { + return createDisplayPowerController(displayId, uniqueId, /* isEnabled= */ true); + } + + private DisplayPowerControllerHolder createDisplayPowerController(int displayId, + String uniqueId, boolean isEnabled) { final DisplayPowerState displayPowerState = mock(DisplayPowerState.class); final DualRampAnimator<DisplayPowerState> animator = mock(DualRampAnimator.class); final AutomaticBrightnessController automaticBrightnessController = @@ -492,9 +644,12 @@ public final class DisplayPowerControllerTest { final BrightnessMappingStrategy brightnessMappingStrategy = mock(BrightnessMappingStrategy.class); final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class); + final ScreenOffBrightnessSensorController screenOffBrightnessSensorController = + mock(ScreenOffBrightnessSensorController.class); DisplayPowerController.Injector injector = new TestInjector(displayPowerState, animator, - automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels); + automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels, + screenOffBrightnessSensorController); final LogicalDisplay display = mock(LogicalDisplay.class); final DisplayDevice device = mock(DisplayDevice.class); @@ -502,7 +657,7 @@ public final class DisplayPowerControllerTest { final BrightnessSetting brightnessSetting = mock(BrightnessSetting.class); final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class); - setUpDisplay(displayId, uniqueId, display, device, config); + setUpDisplay(displayId, uniqueId, display, device, config, isEnabled); final DisplayPowerController dpc = new DisplayPowerController( mContextSpy, injector, mDisplayPowerCallbacksMock, mHandler, @@ -511,7 +666,7 @@ public final class DisplayPowerControllerTest { hbmMetadata, /* bootCompleted= */ false); return new DisplayPowerControllerHolder(dpc, displayPowerState, brightnessSetting, animator, - automaticBrightnessController); + automaticBrightnessController, screenOffBrightnessSensorController, hbmMetadata); } /** @@ -524,16 +679,22 @@ public final class DisplayPowerControllerTest { public final BrightnessSetting brightnessSetting; public final DualRampAnimator<DisplayPowerState> animator; public final AutomaticBrightnessController automaticBrightnessController; + public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController; + public final HighBrightnessModeMetadata hbmMetadata; DisplayPowerControllerHolder(DisplayPowerController dpc, DisplayPowerState displayPowerState, BrightnessSetting brightnessSetting, DualRampAnimator<DisplayPowerState> animator, - AutomaticBrightnessController automaticBrightnessController) { + AutomaticBrightnessController automaticBrightnessController, + ScreenOffBrightnessSensorController screenOffBrightnessSensorController, + HighBrightnessModeMetadata hbmMetadata) { this.dpc = dpc; this.displayPowerState = displayPowerState; this.brightnessSetting = brightnessSetting; this.animator = animator; this.automaticBrightnessController = automaticBrightnessController; + this.screenOffBrightnessSensorController = screenOffBrightnessSensorController; + this.hbmMetadata = hbmMetadata; } } @@ -543,16 +704,19 @@ public final class DisplayPowerControllerTest { private final AutomaticBrightnessController mAutomaticBrightnessController; private final BrightnessMappingStrategy mBrightnessMappingStrategy; private final HysteresisLevels mHysteresisLevels; + private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController; TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator, AutomaticBrightnessController automaticBrightnessController, BrightnessMappingStrategy brightnessMappingStrategy, - HysteresisLevels hysteresisLevels) { + HysteresisLevels hysteresisLevels, + ScreenOffBrightnessSensorController screenOffBrightnessSensorController) { mDisplayPowerState = dps; mAnimator = animator; mAutomaticBrightnessController = automaticBrightnessController; mBrightnessMappingStrategy = brightnessMappingStrategy; mHysteresisLevels = hysteresisLevels; + mScreenOffBrightnessSensorController = screenOffBrightnessSensorController; } @Override @@ -616,5 +780,13 @@ public final class DisplayPowerControllerTest { float minBrighteningThreshold, boolean potentialOldBrightnessRange) { return mHysteresisLevels; } + + @Override + ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( + SensorManager sensorManager, Sensor lightSensor, Handler handler, + ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux, + BrightnessMappingStrategy brightnessMapper) { + return mScreenOffBrightnessSensorController; + } } } |