| /* |
| * Copyright (C) 2022 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; |
| |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; |
| import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; |
| |
| import static org.junit.Assert.assertNotNull; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.ArgumentMatchers.anyBoolean; |
| import static org.mockito.ArgumentMatchers.anyFloat; |
| import static org.mockito.ArgumentMatchers.anyInt; |
| import static org.mockito.ArgumentMatchers.anyLong; |
| import static org.mockito.ArgumentMatchers.anyString; |
| import static org.mockito.ArgumentMatchers.eq; |
| import static org.mockito.ArgumentMatchers.isA; |
| import static org.mockito.ArgumentMatchers.isNull; |
| 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.reset; |
| import static org.mockito.Mockito.spy; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.when; |
| |
| import android.app.ActivityManager; |
| import android.content.Context; |
| import android.content.res.Resources; |
| import android.hardware.Sensor; |
| import android.hardware.SensorEventListener; |
| import android.hardware.SensorManager; |
| import android.hardware.display.BrightnessInfo; |
| import android.hardware.display.DisplayManagerInternal; |
| import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks; |
| import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; |
| import android.os.Handler; |
| import android.os.IBinder; |
| import android.os.Looper; |
| import android.os.PowerManager; |
| import android.os.SystemProperties; |
| import android.os.UserHandle; |
| import android.os.test.TestLooper; |
| import android.platform.test.annotations.RequiresFlagsDisabled; |
| import android.platform.test.annotations.RequiresFlagsEnabled; |
| import android.platform.test.flag.junit.CheckFlagsRule; |
| import android.platform.test.flag.junit.DeviceFlagsValueProvider; |
| import android.provider.Settings; |
| import android.testing.TestableContext; |
| import android.util.FloatProperty; |
| import android.view.Display; |
| import android.view.DisplayInfo; |
| |
| import androidx.test.ext.junit.runners.AndroidJUnit4; |
| import androidx.test.filters.FlakyTest; |
| import androidx.test.filters.SmallTest; |
| import androidx.test.platform.app.InstrumentationRegistry; |
| |
| import com.android.internal.util.test.LocalServiceKeeperRule; |
| import com.android.modules.utils.testing.ExtendedMockitoRule; |
| 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.feature.DisplayManagerFlags; |
| import com.android.server.display.feature.flags.Flags; |
| import com.android.server.display.layout.Layout; |
| import com.android.server.display.whitebalance.DisplayWhiteBalanceController; |
| import com.android.server.policy.WindowManagerPolicy; |
| import com.android.server.testutils.OffsettableClock; |
| |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.Captor; |
| import org.mockito.Mock; |
| import org.mockito.quality.Strictness; |
| import org.mockito.stubbing.Answer; |
| |
| import java.util.List; |
| |
| |
| @SmallTest |
| @RunWith(AndroidJUnit4.class) |
| public final class DisplayPowerControllerTest { |
| private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY; |
| private static final String UNIQUE_ID = "unique_id_test123"; |
| private static final int FOLLOWER_DISPLAY_ID = DISPLAY_ID + 1; |
| private static final String FOLLOWER_UNIQUE_ID = "unique_id_456"; |
| private static final int SECOND_FOLLOWER_DISPLAY_ID = FOLLOWER_DISPLAY_ID + 1; |
| private static final String SECOND_FOLLOWER_UNIQUE_DISPLAY_ID = "unique_id_789"; |
| private static final float PROX_SENSOR_MAX_RANGE = 5; |
| private static final float BRIGHTNESS_RAMP_RATE_MINIMUM = 0.0f; |
| private static final float BRIGHTNESS_RAMP_RATE_FAST_DECREASE = 0.3f; |
| private static final float BRIGHTNESS_RAMP_RATE_FAST_INCREASE = 0.4f; |
| private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE = 0.1f; |
| private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE = 0.2f; |
| private static final float BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE = 0.5f; |
| private static final float BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE = 0.6f; |
| |
| private static final long BRIGHTNESS_RAMP_INCREASE_MAX = 1000; |
| private static final long BRIGHTNESS_RAMP_DECREASE_MAX = 2000; |
| private static final long BRIGHTNESS_RAMP_INCREASE_MAX_IDLE = 3000; |
| private static final long BRIGHTNESS_RAMP_DECREASE_MAX_IDLE = 4000; |
| |
| private OffsettableClock mClock; |
| private TestLooper mTestLooper; |
| private Handler mHandler; |
| private DisplayPowerControllerHolder mHolder; |
| private Sensor mProxSensor; |
| |
| @Mock |
| private DisplayPowerCallbacks mDisplayPowerCallbacksMock; |
| @Mock |
| private SensorManager mSensorManagerMock; |
| @Mock |
| private DisplayBlanker mDisplayBlankerMock; |
| @Mock |
| private BrightnessTracker mBrightnessTrackerMock; |
| @Mock |
| private WindowManagerPolicy mWindowManagerPolicyMock; |
| @Mock |
| private PowerManager mPowerManagerMock; |
| @Mock |
| private ColorDisplayService.ColorDisplayServiceInternal mCdsiMock; |
| @Mock |
| private DisplayWhiteBalanceController mDisplayWhiteBalanceControllerMock; |
| @Mock |
| private DisplayManagerFlags mDisplayManagerFlagsMock; |
| @Mock |
| private DisplayManagerInternal.DisplayOffloadSession mDisplayOffloadSession; |
| |
| @Captor |
| private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor; |
| |
| @Rule |
| public final TestableContext mContext = new TestableContext( |
| InstrumentationRegistry.getInstrumentation().getContext()); |
| |
| @Rule |
| public final ExtendedMockitoRule mExtendedMockitoRule = |
| new ExtendedMockitoRule.Builder(this) |
| .setStrictness(Strictness.LENIENT) |
| .spyStatic(SystemProperties.class) |
| .spyStatic(BatteryStatsService.class) |
| .spyStatic(ActivityManager.class) |
| .build(); |
| |
| @Rule |
| public LocalServiceKeeperRule mLocalServiceKeeperRule = new LocalServiceKeeperRule(); |
| |
| @Rule |
| public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); |
| |
| @Before |
| public void setUp() throws Exception { |
| mClock = new OffsettableClock.Stopped(); |
| mTestLooper = new TestLooper(mClock::now); |
| mHandler = new Handler(mTestLooper.getLooper()); |
| |
| // Set some settings to minimize unexpected events and have a consistent starting state |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); |
| Settings.System.putFloatForUser(mContext.getContentResolver(), |
| Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0, UserHandle.USER_CURRENT); |
| |
| mLocalServiceKeeperRule.overrideLocalService( |
| WindowManagerPolicy.class, mWindowManagerPolicyMock); |
| mLocalServiceKeeperRule.overrideLocalService( |
| ColorDisplayService.ColorDisplayServiceInternal.class, mCdsiMock); |
| |
| mContext.addMockSystemService(PowerManager.class, mPowerManagerMock); |
| |
| mContext.getOrCreateTestableResources().addOverride( |
| com.android.internal.R.bool.config_displayColorFadeDisabled, false); |
| |
| doAnswer((Answer<Void>) invocationOnMock -> null).when(() -> |
| SystemProperties.set(anyString(), any())); |
| doAnswer((Answer<Void>) invocationOnMock -> null).when(BatteryStatsService::getService); |
| doAnswer((Answer<Boolean>) invocationOnMock -> false) |
| .when(ActivityManager::isLowRamDeviceStatic); |
| |
| setUpSensors(); |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| } |
| |
| @Test |
| public void testReleaseProxSuspendBlockersOnExit() throws Exception { |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| // Send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState to start listener for the prox sensor |
| advanceTime(1); |
| |
| SensorEventListener listener = getSensorEventListener(mProxSensor); |
| assertNotNull(listener); |
| |
| listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 5)); |
| advanceTime(1); |
| |
| // two times, one for unfinished business and one for proximity |
| verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker( |
| mHolder.dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID)); |
| verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker( |
| mHolder.dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID)); |
| |
| mHolder.dpc.stop(); |
| advanceTime(1); |
| |
| // two times, one for unfinished business and one for proximity |
| verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker( |
| mHolder.dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID)); |
| verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker( |
| mHolder.dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID)); |
| } |
| |
| @Test |
| public void testScreenOffBecauseOfProximity() throws Exception { |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| // Send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState to start listener for the prox sensor |
| advanceTime(1); |
| |
| SensorEventListener listener = getSensorEventListener(mProxSensor); |
| assertNotNull(listener); |
| |
| // Send a positive proximity event |
| listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); |
| advanceTime(1); |
| |
| // The display should have been turned off |
| verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); |
| |
| clearInvocations(mHolder.displayPowerState); |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); |
| // Send a negative proximity event |
| listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, |
| (int) PROX_SENSOR_MAX_RANGE + 1)); |
| // Advance time by less than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY |
| advanceTime(1); |
| |
| // The prox sensor is debounced so the display should not have been turned back on yet |
| verify(mHolder.displayPowerState, never()).setScreenState(Display.STATE_ON); |
| |
| // Advance time by more than PROXIMITY_SENSOR_NEGATIVE_DEBOUNCE_DELAY |
| advanceTime(1000); |
| |
| // The display should have been turned back on |
| verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); |
| } |
| |
| @Test |
| public void testScreenOffBecauseOfProximity_ProxSensorGone() throws Exception { |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| // Send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState to start listener for the prox sensor |
| advanceTime(1); |
| |
| SensorEventListener listener = getSensorEventListener(mProxSensor); |
| assertNotNull(listener); |
| |
| // Send a positive proximity event |
| listener.onSensorChanged(TestUtils.createSensorEvent(mProxSensor, /* value= */ 1)); |
| advanceTime(1); |
| |
| // The display should have been turned off |
| verify(mHolder.displayPowerState).setScreenState(Display.STATE_OFF); |
| |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); |
| // The display device changes and we no longer have a prox sensor |
| reset(mSensorManagerMock); |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mock(DisplayDeviceConfig.class), /* isEnabled= */ true); |
| mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); |
| |
| advanceTime(1); // Run updatePowerState |
| |
| // The display should have been turned back on and the listener should have been |
| // unregistered |
| verify(mHolder.displayPowerState).setScreenState(Display.STATE_ON); |
| verify(mSensorManagerMock).unregisterListener(listener); |
| } |
| |
| @Test |
| public void testProximitySensorListenerNotRegisteredForNonDefaultDisplay() { |
| DisplayPowerControllerHolder followerDpc = |
| createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); |
| |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| // send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| followerDpc.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState |
| advanceTime(1); |
| |
| verify(mSensorManagerMock, never()).registerListener(any(SensorEventListener.class), |
| eq(mProxSensor), anyInt(), any(Handler.class)); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 294107062) |
| public void testDisplayBrightnessFollowers_BothDpcsSupportNits() { |
| DisplayPowerControllerHolder followerDpc = |
| createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = |
| ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); |
| |
| mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); |
| |
| // Test different float scale values |
| float leadBrightness = 0.3f; |
| float followerBrightness = 0.4f; |
| float nits = 300; |
| when(mHolder.automaticBrightnessController.convertToNits(leadBrightness)).thenReturn(nits); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(followerBrightness); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(leadBrightness); |
| listener.onBrightnessChanged(leadBrightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(leadBrightness); |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(followerBrightness); |
| clearInvocations(mHolder.animator, followerDpc.animator); |
| |
| // Test the same float scale value |
| float brightness = 0.6f; |
| nits = 600; |
| when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(brightness); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); |
| listener.onBrightnessChanged(brightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 294107062) |
| public void testDisplayBrightnessFollowers_FollowerDoesNotSupportNits() { |
| DisplayPowerControllerHolder followerDpc = |
| createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = |
| ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); |
| |
| mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); |
| |
| float brightness = 0.3f; |
| when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(300f); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(anyFloat())) |
| .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); |
| listener.onBrightnessChanged(brightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 294107062) |
| public void testDisplayBrightnessFollowers_LeadDpcDoesNotSupportNits() { |
| DisplayPowerControllerHolder followerDpc = |
| createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = |
| ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); |
| |
| mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); |
| |
| float brightness = 0.3f; |
| when(mHolder.automaticBrightnessController.convertToNits(anyFloat())).thenReturn(-1f); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); |
| listener.onBrightnessChanged(brightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 294107062) |
| public void testDisplayBrightnessFollowers_NeitherDpcSupportsNits() { |
| DisplayPowerControllerHolder followerDpc = |
| createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = |
| ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); |
| |
| mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); |
| |
| float brightness = 0.3f; |
| when(mHolder.automaticBrightnessController.convertToNits(anyFloat())).thenReturn(-1f); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(anyFloat())) |
| .thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); |
| listener.onBrightnessChanged(brightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 294107062) |
| public void testDisplayBrightnessFollowers_AutomaticBrightness() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| DisplayPowerControllerHolder followerDpc = |
| createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| float leadBrightness = 0.1f; |
| float rawLeadBrightness = 0.3f; |
| float followerBrightness = 0.4f; |
| float nits = 300; |
| float ambientLux = 3000; |
| when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness()) |
| .thenReturn(rawLeadBrightness); |
| when(mHolder.automaticBrightnessController |
| .getAutomaticScreenBrightness(any(BrightnessEvent.class))) |
| .thenReturn(leadBrightness); |
| when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness)) |
| .thenReturn(nits); |
| when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(followerBrightness); |
| |
| mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| // One triggered by handleBrightnessModeChange, another triggered by setBrightnessToFollow |
| verify(followerDpc.hbmController, times(2)).onAmbientLuxChange(ambientLux); |
| verify(followerDpc.animator, times(2)).animateTo(eq(followerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(leadBrightness); |
| when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(followerBrightness); |
| clearInvocations(mHolder.animator, followerDpc.animator); |
| |
| leadBrightness = 0.05f; |
| rawLeadBrightness = 0.2f; |
| followerBrightness = 0.3f; |
| nits = 200; |
| ambientLux = 2000; |
| when(mHolder.automaticBrightnessController.getRawAutomaticScreenBrightness()) |
| .thenReturn(rawLeadBrightness); |
| when(mHolder.automaticBrightnessController |
| .getAutomaticScreenBrightness(any(BrightnessEvent.class))) |
| .thenReturn(leadBrightness); |
| when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness)) |
| .thenReturn(nits); |
| when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(followerBrightness); |
| |
| mHolder.dpc.updateBrightness(); |
| advanceTime(1); // Run updatePowerState |
| |
| // The second time, the animation rate should be slow |
| verify(mHolder.animator).animateTo(eq(leadBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE), eq(false)); |
| verify(followerDpc.hbmController).onAmbientLuxChange(ambientLux); |
| verify(followerDpc.animator).animateTo(eq(followerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE), eq(false)); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 294107062) |
| public void testDisplayBrightnessFollowersRemoval_RemoveSingleFollower() { |
| DisplayPowerControllerHolder followerDpc = createDisplayPowerController(FOLLOWER_DISPLAY_ID, |
| FOLLOWER_UNIQUE_ID); |
| DisplayPowerControllerHolder secondFollowerDpc = createDisplayPowerController( |
| SECOND_FOLLOWER_DISPLAY_ID, SECOND_FOLLOWER_UNIQUE_DISPLAY_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(followerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(secondFollowerDpc.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| followerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| secondFollowerDpc.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = |
| ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); |
| |
| // Set the initial brightness on the DPC we're going to remove so we have a fixed value for |
| // it to return to. |
| listenerCaptor = ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(followerDpc.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener followerListener = listenerCaptor.getValue(); |
| final float initialFollowerBrightness = 0.3f; |
| when(followerDpc.brightnessSetting.getBrightness()).thenReturn(initialFollowerBrightness); |
| followerListener.onBrightnessChanged(initialFollowerBrightness); |
| advanceTime(1); |
| verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(followerDpc.displayPowerState.getScreenBrightness()) |
| .thenReturn(initialFollowerBrightness); |
| |
| mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc); |
| mHolder.dpc.addDisplayBrightnessFollower(secondFollowerDpc.dpc); |
| clearInvocations(followerDpc.animator); |
| |
| // Validate both followers are correctly registered and receiving brightness updates |
| float brightness = 0.6f; |
| float nits = 600; |
| when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(brightness); |
| when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(brightness); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); |
| listener.onBrightnessChanged(brightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerDpc.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); |
| when(followerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness); |
| when(secondFollowerDpc.displayPowerState.getScreenBrightness()).thenReturn(brightness); |
| clearInvocations(mHolder.animator, followerDpc.animator, secondFollowerDpc.animator); |
| |
| // Remove the first follower and validate it goes back to its original brightness. |
| mHolder.dpc.removeDisplayBrightnessFollower(followerDpc.dpc); |
| advanceTime(1); |
| verify(followerDpc.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), eq(false)); |
| |
| when(followerDpc.displayPowerState.getScreenBrightness()) |
| .thenReturn(initialFollowerBrightness); |
| clearInvocations(followerDpc.animator); |
| |
| // Change the brightness of the lead display and validate only the second follower responds |
| brightness = 0.7f; |
| nits = 700; |
| when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); |
| when(followerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(brightness); |
| when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(brightness); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); |
| listener.onBrightnessChanged(brightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerDpc.animator, never()).animateTo(anyFloat(), anyFloat(), anyFloat(), |
| anyBoolean()); |
| verify(secondFollowerDpc.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| } |
| |
| @Test |
| @FlakyTest(bugId = 294107062) |
| public void testDisplayBrightnessFollowersRemoval_RemoveAllFollowers() { |
| DisplayPowerControllerHolder followerHolder = |
| createDisplayPowerController(FOLLOWER_DISPLAY_ID, FOLLOWER_UNIQUE_ID); |
| DisplayPowerControllerHolder secondFollowerHolder = |
| createDisplayPowerController(SECOND_FOLLOWER_DISPLAY_ID, |
| SECOND_FOLLOWER_UNIQUE_DISPLAY_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(followerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(secondFollowerHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| followerHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| secondFollowerHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor = |
| ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue(); |
| |
| // Set the initial brightness on the DPCs we're going to remove so we have a fixed value for |
| // it to return to. |
| listenerCaptor = ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(followerHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener followerListener = listenerCaptor.getValue(); |
| listenerCaptor = ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class); |
| verify(secondFollowerHolder.brightnessSetting).registerListener(listenerCaptor.capture()); |
| BrightnessSetting.BrightnessSettingListener secondFollowerListener = |
| listenerCaptor.getValue(); |
| final float initialFollowerBrightness = 0.3f; |
| when(followerHolder.brightnessSetting.getBrightness()).thenReturn( |
| initialFollowerBrightness); |
| when(secondFollowerHolder.brightnessSetting.getBrightness()).thenReturn( |
| initialFollowerBrightness); |
| followerListener.onBrightnessChanged(initialFollowerBrightness); |
| secondFollowerListener.onBrightnessChanged(initialFollowerBrightness); |
| advanceTime(1); |
| verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(followerHolder.displayPowerState.getScreenBrightness()) |
| .thenReturn(initialFollowerBrightness); |
| when(secondFollowerHolder.displayPowerState.getScreenBrightness()) |
| .thenReturn(initialFollowerBrightness); |
| |
| mHolder.dpc.addDisplayBrightnessFollower(followerHolder.dpc); |
| mHolder.dpc.addDisplayBrightnessFollower(secondFollowerHolder.dpc); |
| clearInvocations(followerHolder.animator, secondFollowerHolder.animator); |
| |
| // Validate both followers are correctly registered and receiving brightness updates |
| float brightness = 0.6f; |
| float nits = 600; |
| when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); |
| when(followerHolder.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(brightness); |
| when(secondFollowerHolder.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(brightness); |
| when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness); |
| listener.onBrightnessChanged(brightness); |
| advanceTime(1); // Send messages, run updatePowerState |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(followerHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| verify(secondFollowerHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); |
| when(followerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); |
| when(secondFollowerHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); |
| clearInvocations(mHolder.animator, followerHolder.animator, secondFollowerHolder.animator); |
| |
| // Stop the lead DPC and validate that the followers go back to their original brightness. |
| mHolder.dpc.stop(); |
| advanceTime(1); |
| verify(followerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), eq(false)); |
| verify(secondFollowerHolder.animator).animateTo(eq(initialFollowerBrightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_DECREASE), eq(false)); |
| clearInvocations(followerHolder.animator, secondFollowerHolder.animator); |
| } |
| |
| @Test |
| public void testDoesNotSetScreenStateForNonDefaultDisplayUntilBootCompleted() { |
| // We should still set screen state for the default display |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| verify(mHolder.displayPowerState, times(2)).setScreenState(anyInt()); |
| |
| mHolder = createDisplayPowerController(42, UNIQUE_ID); |
| |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); |
| |
| mHolder.dpc.onBootCompleted(); |
| advanceTime(1); // Run updatePowerState |
| verify(mHolder.displayPowerState).setScreenState(anyInt()); |
| } |
| |
| @Test |
| public void testSetScreenOffBrightnessSensorEnabled_DisplayIsOff() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| |
| 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(), eq(false)); |
| } |
| |
| @Test |
| public void testSetScreenOffBrightnessSensorEnabled_DisplayIsInDoze() { |
| mContext.getOrCreateTestableResources().addOverride( |
| com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false); |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_DOZE; |
| 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(), eq(false)); |
| } |
| |
| @Test |
| public void testSetScreenOffBrightnessSensorDisabled_AutoBrightnessIsDisabled() { |
| // Tests are set up with manual brightness by default, so no need to set it here. |
| 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() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| |
| 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); |
| } |
| |
| @Test |
| public void testStopScreenOffBrightnessSensorControllerWhenDisplayDeviceChanges() { |
| // New display device |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mock(DisplayDeviceConfig.class), /* isEnabled= */ true); |
| |
| mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.screenOffBrightnessSensorController).stop(); |
| } |
| |
| @Test |
| public void testAutoBrightnessEnabled_DisplayIsOn() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.automaticBrightnessController).configure( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, |
| /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, |
| /* userChangedBrightness= */ false, /* adjustment= */ 0, |
| /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT, |
| /* shouldResetShortTermModel= */ false |
| ); |
| verify(mHolder.hbmController) |
| .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED); |
| } |
| |
| @Test |
| public void testAutoBrightnessEnabled_DisplayIsInDoze() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| mContext.getOrCreateTestableResources().addOverride( |
| com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true); |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_DOZE; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.automaticBrightnessController).configure( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED, |
| /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, |
| /* userChangedBrightness= */ false, /* adjustment= */ 0, |
| /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE, |
| /* shouldResetShortTermModel= */ false |
| ); |
| verify(mHolder.hbmController) |
| .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED); |
| } |
| |
| @Test |
| public void testAutoBrightnessDisabled_ManualBrightnessMode() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| // One triggered by the test, the other by handleBrightnessModeChange |
| verify(mHolder.automaticBrightnessController, times(2)).configure( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, |
| /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, |
| /* userChangedBrightness= */ false, /* adjustment= */ 0, |
| /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT, |
| /* shouldResetShortTermModel= */ false |
| ); |
| verify(mHolder.hbmController, times(2)) |
| .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED); |
| } |
| |
| @Test |
| public void testAutoBrightnessDisabled_DisplayIsOff() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_OFF; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_OFF); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.automaticBrightnessController).configure( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE, |
| /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, |
| /* userChangedBrightness= */ false, /* adjustment= */ 0, |
| /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_OFF, |
| /* shouldResetShortTermModel= */ false |
| ); |
| verify(mHolder.hbmController).setAutoBrightnessEnabled( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE); |
| } |
| |
| @Test |
| public void testAutoBrightnessDisabled_DisplayIsInDoze() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| mContext.getOrCreateTestableResources().addOverride( |
| com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false); |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_DOZE; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.automaticBrightnessController).configure( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE, |
| /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, |
| /* userChangedBrightness= */ false, /* adjustment= */ 0, |
| /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE, |
| /* shouldResetShortTermModel= */ false |
| ); |
| verify(mHolder.hbmController).setAutoBrightnessEnabled( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE); |
| } |
| |
| @Test |
| public void testAutoBrightnessDisabled_FollowerDisplay() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| mHolder.dpc.setBrightnessToFollow(0.3f, -1, 0, /* slowChange= */ false); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| // One triggered by the test, the other by handleBrightnessModeChange |
| verify(mHolder.automaticBrightnessController, times(2)).configure( |
| AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED, |
| /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT, |
| /* userChangedBrightness= */ false, /* adjustment= */ 0, |
| /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_BRIGHT, |
| /* shouldResetShortTermModel= */ false |
| ); |
| |
| // HBM should be allowed for the follower display |
| verify(mHolder.hbmController) |
| .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED); |
| } |
| |
| @Test |
| public void testBrightnessNitsPersistWhenDisplayDeviceChanges() { |
| float brightness = 0.3f; |
| float nits = 500; |
| mContext.getOrCreateTestableResources().addOverride( |
| com.android.internal.R.bool.config_persistBrightnessNitsForDefaultDisplay, |
| true); |
| |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits); |
| |
| mHolder.dpc.setBrightness(brightness); |
| verify(mHolder.brightnessSetting).setBrightnessNitsForDefaultDisplay(nits); |
| |
| float newBrightness = 0.4f; |
| when(mHolder.brightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits); |
| when(mHolder.automaticBrightnessController.convertToFloatScale(nits)) |
| .thenReturn(newBrightness); |
| // New display device |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mock(DisplayDeviceConfig.class), /* isEnabled= */ true); |
| mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| // One triggered by handleBrightnessModeChange, another triggered by onDisplayChanged |
| verify(mHolder.animator, times(2)).animateTo(eq(newBrightness), anyFloat(), anyFloat(), |
| eq(false)); |
| } |
| |
| @Test |
| public void testShortTermModelPersistsWhenDisplayDeviceChanges() { |
| float lux = 2000; |
| float brightness = 0.4f; |
| float nits = 500; |
| when(mHolder.brightnessMappingStrategy.getUserLux()).thenReturn(lux); |
| when(mHolder.brightnessMappingStrategy.getUserBrightness()).thenReturn(brightness); |
| when(mHolder.brightnessMappingStrategy.convertToNits(brightness)).thenReturn(nits); |
| when(mHolder.brightnessMappingStrategy.convertToFloatScale(nits)).thenReturn(brightness); |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); |
| clearInvocations(mHolder.injector); |
| |
| // New display device |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mock(DisplayDeviceConfig.class), /* isEnabled= */ true); |
| mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); |
| advanceTime(1); |
| |
| verify(mHolder.injector).getAutomaticBrightnessController( |
| any(AutomaticBrightnessController.Callbacks.class), |
| any(Looper.class), |
| eq(mSensorManagerMock), |
| /* lightSensor= */ any(), |
| eq(mHolder.brightnessMappingStrategy), |
| /* lightSensorWarmUpTime= */ anyInt(), |
| /* brightnessMin= */ anyFloat(), |
| /* brightnessMax= */ anyFloat(), |
| /* dozeScaleFactor */ anyFloat(), |
| /* lightSensorRate= */ anyInt(), |
| /* initialLightSensorRate= */ anyInt(), |
| /* brighteningLightDebounceConfig */ anyLong(), |
| /* darkeningLightDebounceConfig */ anyLong(), |
| /* brighteningLightDebounceConfigIdle= */ anyLong(), |
| /* darkeningLightDebounceConfigIdle= */ anyLong(), |
| /* resetAmbientLuxAfterWarmUpConfig= */ anyBoolean(), |
| any(HysteresisLevels.class), |
| any(HysteresisLevels.class), |
| any(HysteresisLevels.class), |
| any(HysteresisLevels.class), |
| eq(mContext), |
| any(BrightnessRangeController.class), |
| any(BrightnessThrottler.class), |
| /* idleModeBrightnessMapper= */ isNull(), |
| /* ambientLightHorizonShort= */ anyInt(), |
| /* ambientLightHorizonLong= */ anyInt(), |
| eq(lux), |
| eq(brightness) |
| ); |
| } |
| |
| @Test |
| public void testUpdateBrightnessThrottlingDataId() { |
| mHolder.display.getDisplayInfoLocked().thermalBrightnessThrottlingDataId = |
| "throttling-data-id"; |
| clearInvocations(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig()); |
| |
| mHolder.dpc.onDisplayChanged(mHolder.hbmMetadata, Layout.NO_LEAD_DISPLAY); |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.display.getPrimaryDisplayDeviceLocked().getDisplayDeviceConfig()) |
| .getThermalBrightnessThrottlingDataMapByThrottlingId(); |
| } |
| |
| @Test |
| public void testSetBrightness_BrightnessShouldBeClamped() { |
| float clampedBrightness = 0.6f; |
| when(mHolder.hbmController.getCurrentBrightnessMax()).thenReturn(clampedBrightness); |
| |
| mHolder.dpc.setBrightness(PowerManager.BRIGHTNESS_MAX); |
| |
| verify(mHolder.brightnessSetting).setBrightness(clampedBrightness); |
| } |
| |
| @Test |
| public void testDwbcCallsHappenOnHandler() { |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| |
| mHolder.dpc.setAutomaticScreenBrightnessMode(true); |
| verify(mDisplayWhiteBalanceControllerMock, never()).setStrongModeEnabled(true); |
| |
| // dispatch handler looper |
| advanceTime(1); |
| verify(mDisplayWhiteBalanceControllerMock, times(1)).setStrongModeEnabled(true); |
| } |
| |
| @Test |
| public void testRampRatesIdle() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| float brightness = 0.6f; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(mHolder.automaticBrightnessController.isInIdleMode()).thenReturn(true); |
| when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( |
| any(BrightnessEvent.class))).thenReturn(brightness); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(brightness); |
| brightness = 0.05f; |
| when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( |
| any(BrightnessEvent.class))).thenReturn(brightness); |
| |
| mHolder.dpc.updateBrightness(); |
| advanceTime(1); // Run updatePowerState |
| |
| // The second time, the animation rate should be slow |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE), eq(false)); |
| |
| brightness = 0.9f; |
| when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( |
| any(BrightnessEvent.class))).thenReturn(brightness); |
| |
| mHolder.dpc.updateBrightness(); |
| advanceTime(1); // Run updatePowerState |
| // The third time, the animation rate should be slow |
| verify(mHolder.animator).animateTo(eq(brightness), anyFloat(), |
| eq(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE), eq(false)); |
| } |
| |
| @Test |
| public void testDisplayBrightnessHdr_SkipAnimationOnHdrAppearance() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| final float sdrBrightness = 0.1f; |
| final float hdrBrightness = 0.3f; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( |
| any(BrightnessEvent.class))).thenReturn(sdrBrightness); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(sdrBrightness); |
| when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); |
| |
| when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( |
| BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); |
| when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); |
| clearInvocations(mHolder.animator); |
| |
| mHolder.dpc.updateBrightness(); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), |
| eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); |
| } |
| |
| @Test |
| public void testDisplayBrightnessHdr_SkipAnimationOnHdrRemoval() { |
| Settings.System.putInt(mContext.getContentResolver(), |
| Settings.System.SCREEN_BRIGHTNESS_MODE, |
| Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); |
| final float sdrBrightness = 0.1f; |
| final float hdrBrightness = 0.3f; |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness( |
| any(BrightnessEvent.class))).thenReturn(sdrBrightness); |
| |
| when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( |
| BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR); |
| when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness); |
| |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.animator).animateTo(eq(hdrBrightness), eq(sdrBrightness), |
| eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false)); |
| |
| when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(hdrBrightness); |
| when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(sdrBrightness); |
| when(mHolder.hbmController.getHighBrightnessMode()).thenReturn( |
| BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF); |
| |
| clearInvocations(mHolder.animator); |
| |
| mHolder.dpc.updateBrightness(); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.animator).animateTo(eq(sdrBrightness), eq(sdrBrightness), |
| eq(BRIGHTNESS_RAMP_RATE_MINIMUM), eq(false)); |
| } |
| |
| @Test |
| @RequiresFlagsDisabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) |
| public void testRampMaxTimeInteractiveThenIdle() { |
| // Send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState |
| advanceTime(1); |
| |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mHolder.config, /* isEnabled= */ true); |
| |
| verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, |
| BRIGHTNESS_RAMP_DECREASE_MAX); |
| |
| // switch to idle |
| mHolder.dpc.setAutomaticScreenBrightnessMode(/* idle= */ true); |
| advanceTime(1); |
| |
| verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, |
| BRIGHTNESS_RAMP_DECREASE_MAX); |
| } |
| |
| @Test |
| @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) |
| public void testRampMaxTimeInteractiveThenIdle_DifferentValues() { |
| when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); |
| // Send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState |
| advanceTime(1); |
| |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mHolder.config, /* isEnabled= */ true); |
| |
| verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, |
| BRIGHTNESS_RAMP_DECREASE_MAX); |
| |
| // switch to idle |
| mHolder.dpc.setAutomaticScreenBrightnessMode(/* idle= */ true); |
| advanceTime(1); |
| |
| verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, |
| BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); |
| } |
| |
| @Test |
| @RequiresFlagsDisabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) |
| public void testRampMaxTimeIdle() { |
| // Send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState |
| advanceTime(1); |
| |
| // once on setup |
| verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, |
| BRIGHTNESS_RAMP_DECREASE_MAX); |
| |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mHolder.config, /* isEnabled= */ true); |
| |
| // switch to idle mode |
| mHolder.dpc.setAutomaticScreenBrightnessMode(true); |
| |
| // second time when switching to idle screen brightness mode |
| verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX, |
| BRIGHTNESS_RAMP_DECREASE_MAX); |
| } |
| |
| @Test |
| @RequiresFlagsEnabled(Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1) |
| public void testRampMaxTimeIdle_DifferentValues() { |
| when(mDisplayManagerFlagsMock.isAdaptiveTone1Enabled()).thenReturn(true); |
| |
| // Send a display power request |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_BRIGHT; |
| dpr.useProximitySensor = true; |
| mHolder.dpc.requestPowerState(dpr, false /* waitForNegativeProximity */); |
| |
| // Run updatePowerState |
| advanceTime(1); |
| |
| setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class), |
| mHolder.config, /* isEnabled= */ true); |
| |
| // switch to idle mode |
| mHolder.dpc.setAutomaticScreenBrightnessMode(true); |
| |
| verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE, |
| BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); |
| } |
| @Test |
| public void testDozeScreenStateOverride_toSupportedOffloadStateFromDoze_DisplayStateChanges() { |
| // set up. |
| int initState = Display.STATE_DOZE; |
| int supportedTargetState = Display.STATE_DOZE_SUSPEND; |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| doAnswer(invocation -> { |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); |
| return null; |
| }).when(mHolder.displayPowerState).setScreenState(anyInt()); |
| mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); |
| |
| // start with DOZE. |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(initState); |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_DOZE; |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| mHolder.dpc.overrideDozeScreenState(supportedTargetState); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.displayPowerState).setScreenState(supportedTargetState); |
| } |
| |
| @Test |
| public void testDozeScreenStateOverride_toUnSupportedOffloadStateFromDoze_stateRemains() { |
| // set up. |
| int initState = Display.STATE_DOZE; |
| int unSupportedTargetState = Display.STATE_ON; |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f); |
| doAnswer(invocation -> { |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); |
| return null; |
| }).when(mHolder.displayPowerState).setScreenState(anyInt()); |
| mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); |
| |
| // start with DOZE. |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(initState); |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_DOZE; |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| mHolder.dpc.overrideDozeScreenState(unSupportedTargetState); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); |
| } |
| |
| @Test |
| public void testDozeScreenStateOverride_toSupportedOffloadStateFromOFF_stateRemains() { |
| // set up. |
| int initState = Display.STATE_OFF; |
| int supportedTargetState = Display.STATE_DOZE_SUSPEND; |
| mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID); |
| doAnswer(invocation -> { |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(invocation.getArgument(0)); |
| return null; |
| }).when(mHolder.displayPowerState).setScreenState(anyInt()); |
| mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession); |
| |
| // start with OFF. |
| when(mHolder.displayPowerState.getScreenState()).thenReturn(initState); |
| DisplayPowerRequest dpr = new DisplayPowerRequest(); |
| dpr.policy = DisplayPowerRequest.POLICY_OFF; |
| mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false); |
| advanceTime(1); // Run updatePowerState |
| |
| mHolder.dpc.overrideDozeScreenState(supportedTargetState); |
| advanceTime(1); // Run updatePowerState |
| |
| verify(mHolder.displayPowerState, never()).setScreenState(anyInt()); |
| } |
| |
| private void advanceTime(long timeMs) { |
| mClock.fastForward(timeMs); |
| mTestLooper.dispatchAll(); |
| } |
| |
| private void setUpSensors() throws Exception { |
| mProxSensor = TestUtils.createSensor(Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY, |
| PROX_SENSOR_MAX_RANGE); |
| Sensor screenOffBrightnessSensor = TestUtils.createSensor( |
| Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT); |
| when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL))) |
| .thenReturn(List.of(mProxSensor, screenOffBrightnessSensor)); |
| } |
| |
| private SensorEventListener getSensorEventListener(Sensor sensor) { |
| verify(mSensorManagerMock).registerListener(mSensorEventListenerCaptor.capture(), |
| eq(sensor), eq(SensorManager.SENSOR_DELAY_NORMAL), isA(Handler.class)); |
| return mSensorEventListenerCaptor.getValue(); |
| } |
| |
| private void setUpDisplay(int displayId, String uniqueId, LogicalDisplay logicalDisplayMock, |
| DisplayDevice displayDeviceMock, DisplayDeviceConfig displayDeviceConfigMock, |
| boolean isEnabled) { |
| DisplayInfo info = new DisplayInfo(); |
| DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo(); |
| deviceInfo.uniqueId = uniqueId; |
| |
| when(logicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId); |
| when(logicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(displayDeviceMock); |
| when(logicalDisplayMock.getDisplayInfoLocked()).thenReturn(info); |
| when(logicalDisplayMock.isEnabledLocked()).thenReturn(isEnabled); |
| when(logicalDisplayMock.isInTransitionLocked()).thenReturn(false); |
| when(displayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo); |
| when(displayDeviceMock.getUniqueId()).thenReturn(uniqueId); |
| when(displayDeviceMock.getDisplayDeviceConfig()).thenReturn(displayDeviceConfigMock); |
| when(displayDeviceConfigMock.getProximitySensor()).thenReturn( |
| new DisplayDeviceConfig.SensorData() { |
| { |
| type = Sensor.STRING_TYPE_PROXIMITY; |
| name = null; |
| } |
| }); |
| when(displayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500}); |
| when(displayDeviceConfigMock.isAutoBrightnessAvailable()).thenReturn(true); |
| when(displayDeviceConfigMock.getAmbientLightSensor()).thenReturn( |
| new DisplayDeviceConfig.SensorData()); |
| when(displayDeviceConfigMock.getScreenOffBrightnessSensor()).thenReturn( |
| new DisplayDeviceConfig.SensorData() { |
| { |
| type = Sensor.STRING_TYPE_LIGHT; |
| name = null; |
| } |
| }); |
| when(displayDeviceConfigMock.getScreenOffBrightnessSensorValueToLux()) |
| .thenReturn(new int[0]); |
| |
| when(displayDeviceConfigMock.getBrightnessRampFastDecrease()) |
| .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_DECREASE); |
| when(displayDeviceConfigMock.getBrightnessRampFastIncrease()) |
| .thenReturn(BRIGHTNESS_RAMP_RATE_FAST_INCREASE); |
| when(displayDeviceConfigMock.getBrightnessRampSlowDecrease()) |
| .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE); |
| when(displayDeviceConfigMock.getBrightnessRampSlowIncrease()) |
| .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE); |
| when(displayDeviceConfigMock.getBrightnessRampSlowDecreaseIdle()) |
| .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_DECREASE_IDLE); |
| when(displayDeviceConfigMock.getBrightnessRampSlowIncreaseIdle()) |
| .thenReturn(BRIGHTNESS_RAMP_RATE_SLOW_INCREASE_IDLE); |
| |
| when(displayDeviceConfigMock.getBrightnessRampIncreaseMaxMillis()) |
| .thenReturn(BRIGHTNESS_RAMP_INCREASE_MAX); |
| when(displayDeviceConfigMock.getBrightnessRampDecreaseMaxMillis()) |
| .thenReturn(BRIGHTNESS_RAMP_DECREASE_MAX); |
| when(displayDeviceConfigMock.getBrightnessRampIncreaseMaxIdleMillis()) |
| .thenReturn(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE); |
| when(displayDeviceConfigMock.getBrightnessRampDecreaseMaxIdleMillis()) |
| .thenReturn(BRIGHTNESS_RAMP_DECREASE_MAX_IDLE); |
| } |
| |
| 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 = |
| mock(AutomaticBrightnessController.class); |
| final BrightnessMappingStrategy brightnessMappingStrategy = |
| mock(BrightnessMappingStrategy.class); |
| final HysteresisLevels hysteresisLevels = mock(HysteresisLevels.class); |
| final ScreenOffBrightnessSensorController screenOffBrightnessSensorController = |
| mock(ScreenOffBrightnessSensorController.class); |
| final HighBrightnessModeController hbmController = mock(HighBrightnessModeController.class); |
| |
| when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX); |
| |
| DisplayPowerController.Injector injector = spy(new TestInjector(displayPowerState, animator, |
| automaticBrightnessController, brightnessMappingStrategy, hysteresisLevels, |
| screenOffBrightnessSensorController, hbmController)); |
| |
| final LogicalDisplay display = mock(LogicalDisplay.class); |
| final DisplayDevice device = mock(DisplayDevice.class); |
| final HighBrightnessModeMetadata hbmMetadata = mock(HighBrightnessModeMetadata.class); |
| final BrightnessSetting brightnessSetting = mock(BrightnessSetting.class); |
| final DisplayDeviceConfig config = mock(DisplayDeviceConfig.class); |
| |
| setUpDisplay(displayId, uniqueId, display, device, config, isEnabled); |
| |
| final DisplayPowerController dpc = new DisplayPowerController( |
| mContext, injector, mDisplayPowerCallbacksMock, mHandler, |
| mSensorManagerMock, mDisplayBlankerMock, display, |
| mBrightnessTrackerMock, brightnessSetting, () -> {}, |
| hbmMetadata, /* bootCompleted= */ false, mDisplayManagerFlagsMock); |
| |
| return new DisplayPowerControllerHolder(dpc, display, displayPowerState, brightnessSetting, |
| animator, automaticBrightnessController, screenOffBrightnessSensorController, |
| hbmController, hbmMetadata, brightnessMappingStrategy, injector, config); |
| } |
| |
| /** |
| * A class for holding a DisplayPowerController under test and all the mocks specifically |
| * related to it. |
| */ |
| private static class DisplayPowerControllerHolder { |
| public final DisplayPowerController dpc; |
| public final LogicalDisplay display; |
| public final DisplayPowerState displayPowerState; |
| public final BrightnessSetting brightnessSetting; |
| public final DualRampAnimator<DisplayPowerState> animator; |
| public final AutomaticBrightnessController automaticBrightnessController; |
| public final ScreenOffBrightnessSensorController screenOffBrightnessSensorController; |
| public final HighBrightnessModeController hbmController; |
| public final HighBrightnessModeMetadata hbmMetadata; |
| public final BrightnessMappingStrategy brightnessMappingStrategy; |
| public final DisplayPowerController.Injector injector; |
| public final DisplayDeviceConfig config; |
| |
| DisplayPowerControllerHolder(DisplayPowerController dpc, LogicalDisplay display, |
| DisplayPowerState displayPowerState, BrightnessSetting brightnessSetting, |
| DualRampAnimator<DisplayPowerState> animator, |
| AutomaticBrightnessController automaticBrightnessController, |
| ScreenOffBrightnessSensorController screenOffBrightnessSensorController, |
| HighBrightnessModeController hbmController, |
| HighBrightnessModeMetadata hbmMetadata, |
| BrightnessMappingStrategy brightnessMappingStrategy, |
| DisplayPowerController.Injector injector, |
| DisplayDeviceConfig config) { |
| this.dpc = dpc; |
| this.display = display; |
| this.displayPowerState = displayPowerState; |
| this.brightnessSetting = brightnessSetting; |
| this.animator = animator; |
| this.automaticBrightnessController = automaticBrightnessController; |
| this.screenOffBrightnessSensorController = screenOffBrightnessSensorController; |
| this.hbmController = hbmController; |
| this.hbmMetadata = hbmMetadata; |
| this.brightnessMappingStrategy = brightnessMappingStrategy; |
| this.injector = injector; |
| this.config = config; |
| } |
| } |
| |
| private class TestInjector extends DisplayPowerController.Injector { |
| private final DisplayPowerState mDisplayPowerState; |
| private final DualRampAnimator<DisplayPowerState> mAnimator; |
| private final AutomaticBrightnessController mAutomaticBrightnessController; |
| private final BrightnessMappingStrategy mBrightnessMappingStrategy; |
| private final HysteresisLevels mHysteresisLevels; |
| private final ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController; |
| private final HighBrightnessModeController mHighBrightnessModeController; |
| |
| TestInjector(DisplayPowerState dps, DualRampAnimator<DisplayPowerState> animator, |
| AutomaticBrightnessController automaticBrightnessController, |
| BrightnessMappingStrategy brightnessMappingStrategy, |
| HysteresisLevels hysteresisLevels, |
| ScreenOffBrightnessSensorController screenOffBrightnessSensorController, |
| HighBrightnessModeController highBrightnessModeController) { |
| mDisplayPowerState = dps; |
| mAnimator = animator; |
| mAutomaticBrightnessController = automaticBrightnessController; |
| mBrightnessMappingStrategy = brightnessMappingStrategy; |
| mHysteresisLevels = hysteresisLevels; |
| mScreenOffBrightnessSensorController = screenOffBrightnessSensorController; |
| mHighBrightnessModeController = highBrightnessModeController; |
| } |
| |
| @Override |
| DisplayPowerController.Clock getClock() { |
| return mClock::now; |
| } |
| |
| @Override |
| DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade, |
| int displayId, int displayState) { |
| return mDisplayPowerState; |
| } |
| |
| @Override |
| DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps, |
| FloatProperty<DisplayPowerState> firstProperty, |
| FloatProperty<DisplayPowerState> secondProperty) { |
| return mAnimator; |
| } |
| |
| @Override |
| AutomaticBrightnessController getAutomaticBrightnessController( |
| AutomaticBrightnessController.Callbacks callbacks, Looper looper, |
| SensorManager sensorManager, Sensor lightSensor, |
| BrightnessMappingStrategy interactiveModeBrightnessMapper, |
| int lightSensorWarmUpTime, float brightnessMin, float brightnessMax, |
| float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate, |
| long brighteningLightDebounceConfig, long darkeningLightDebounceConfig, |
| long brighteningLightDebounceConfigIdle, long darkeningLightDebounceConfigIdle, |
| boolean resetAmbientLuxAfterWarmUpConfig, |
| HysteresisLevels ambientBrightnessThresholds, |
| HysteresisLevels screenBrightnessThresholds, |
| HysteresisLevels ambientBrightnessThresholdsIdle, |
| HysteresisLevels screenBrightnessThresholdsIdle, Context context, |
| BrightnessRangeController brightnessRangeController, |
| BrightnessThrottler brightnessThrottler, |
| BrightnessMappingStrategy idleModeBrightnessMapper, |
| int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux, |
| float userBrightness) { |
| return mAutomaticBrightnessController; |
| } |
| |
| @Override |
| BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources, |
| DisplayDeviceConfig displayDeviceConfig, |
| DisplayWhiteBalanceController displayWhiteBalanceController) { |
| return mBrightnessMappingStrategy; |
| } |
| |
| @Override |
| HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages, |
| float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, |
| float[] darkeningThresholdLevels, float minDarkeningThreshold, |
| float minBrighteningThreshold) { |
| return mHysteresisLevels; |
| } |
| |
| @Override |
| HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages, |
| float[] darkeningThresholdsPercentages, float[] brighteningThresholdLevels, |
| float[] darkeningThresholdLevels, float minDarkeningThreshold, |
| float minBrighteningThreshold, boolean potentialOldBrightnessRange) { |
| return mHysteresisLevels; |
| } |
| |
| @Override |
| ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( |
| SensorManager sensorManager, Sensor lightSensor, Handler handler, |
| ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux, |
| BrightnessMappingStrategy brightnessMapper) { |
| return mScreenOffBrightnessSensorController; |
| } |
| |
| @Override |
| HighBrightnessModeController getHighBrightnessModeController(Handler handler, int width, |
| int height, IBinder displayToken, String displayUniqueId, float brightnessMin, |
| float brightnessMax, DisplayDeviceConfig.HighBrightnessModeData hbmData, |
| HighBrightnessModeController.HdrBrightnessDeviceConfig hdrBrightnessCfg, |
| Runnable hbmChangeCallback, HighBrightnessModeMetadata hbmMetadata, |
| Context context) { |
| return mHighBrightnessModeController; |
| } |
| |
| @Override |
| DisplayWhiteBalanceController getDisplayWhiteBalanceController(Handler handler, |
| SensorManager sensorManager, Resources resources) { |
| return mDisplayWhiteBalanceControllerMock; |
| } |
| } |
| } |