Merge "Add duplicated DisplayPowerController"

This commit is contained in:
Rupesh Bansal
2022-09-22 17:10:20 +00:00
committed by Android (Google) Code Review
4 changed files with 3312 additions and 5 deletions

View File

@@ -2562,10 +2562,10 @@ public final class DisplayManagerService extends SystemService {
final BrightnessSetting brightnessSetting = new BrightnessSetting(mPersistentDataStore,
display, mSyncRoot);
final DisplayPowerController displayPowerController;
final DisplayPowerControllerInterface displayPowerController;
if (SystemProperties.getInt(PROP_USE_NEW_DISPLAY_POWER_CONTROLLER, 0) == 1) {
displayPowerController = new DisplayPowerController(
displayPowerController = new DisplayPowerController2(
mContext, /* injector= */ null, mDisplayPowerCallbacks, mPowerHandler,
mSensorManager, mDisplayBlanker, display, mBrightnessTracker, brightnessSetting,
() -> handleBrightnessChange(display));

View File

@@ -798,8 +798,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
* Notified when the display is changed. We use this to apply any changes that might be needed
* when displays get swapped on foldable devices. For example, different brightness properties
* of each display need to be properly reflected in AutomaticBrightnessController.
*
* Make sure DisplayManagerService.mSyncRoot is held when this is called
*/
@GuardedBy("DisplayManagerService.mSyncRoot")
@Override
public void onDisplayChanged() {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
@@ -1896,7 +1897,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
},
() -> {
sendUpdatePowerStateLocked();
sendUpdatePowerState();
postBrightnessChangeRunnable();
// TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
if (mAutomaticBrightnessController != null) {
@@ -1912,7 +1913,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
ddConfig != null ? ddConfig.getBrightnessThrottlingData() : null;
return new BrightnessThrottler(mHandler, data,
() -> {
sendUpdatePowerStateLocked();
sendUpdatePowerState();
postBrightnessChangeRunnable();
}, mUniqueDisplayId);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
/*
* 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.verify;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManagerInternal.DisplayPowerCallbacks;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
import android.os.PowerManager;
import android.os.test.TestLooper;
import android.util.FloatProperty;
import android.view.Display;
import android.view.DisplayInfo;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.LocalServices;
import com.android.server.display.RampAnimator.DualRampAnimator;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.testutils.OffsettableClock;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public final class DisplayPowerController2Test {
private static final String UNIQUE_DISPLAY_ID = "unique_id_test123";
private static final int DISPLAY_ID = 42;
private OffsettableClock mClock;
private TestLooper mTestLooper;
private Handler mHandler;
private DisplayPowerController2.Injector mInjector;
private Context mContextSpy;
@Mock
private DisplayPowerCallbacks mDisplayPowerCallbacksMock;
@Mock
private SensorManager mSensorManagerMock;
@Mock
private DisplayBlanker mDisplayBlankerMock;
@Mock
private LogicalDisplay mLogicalDisplayMock;
@Mock
private DisplayDevice mDisplayDeviceMock;
@Mock
private BrightnessTracker mBrightnessTrackerMock;
@Mock
private BrightnessSetting mBrightnessSettingMock;
@Mock
private WindowManagerPolicy mWindowManagerPolicyMock;
@Mock
private PowerManager mPowerManagerMock;
@Mock
private Resources mResourcesMock;
@Mock
private DisplayDeviceConfig mDisplayDeviceConfigMock;
@Mock
private DisplayPowerState mDisplayPowerStateMock;
@Mock
private DualRampAnimator<DisplayPowerState> mDualRampAnimatorMock;
@Captor
private ArgumentCaptor<SensorEventListener> mSensorEventListenerCaptor;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContextSpy = spy(new ContextWrapper(ApplicationProvider.getApplicationContext()));
mClock = new OffsettableClock.Stopped();
mTestLooper = new TestLooper(mClock::now);
mHandler = new Handler(mTestLooper.getLooper());
mInjector = new DisplayPowerController2.Injector() {
@Override
DisplayPowerController2.Clock getClock() {
return mClock::now;
}
@Override
DisplayPowerState getDisplayPowerState(DisplayBlanker blanker, ColorFade colorFade,
int displayId, int displayState) {
return mDisplayPowerStateMock;
}
@Override
DualRampAnimator<DisplayPowerState> getDualRampAnimator(DisplayPowerState dps,
FloatProperty<DisplayPowerState> firstProperty,
FloatProperty<DisplayPowerState> secondProperty) {
return mDualRampAnimatorMock;
}
};
addLocalServiceMock(WindowManagerPolicy.class, mWindowManagerPolicyMock);
when(mContextSpy.getSystemService(eq(PowerManager.class))).thenReturn(mPowerManagerMock);
when(mContextSpy.getResources()).thenReturn(mResourcesMock);
}
@After
public void tearDown() {
LocalServices.removeServiceForTest(WindowManagerPolicy.class);
}
@Test
public void testReleaseProxSuspendBlockersOnExit() throws Exception {
setUpDisplay(DISPLAY_ID, UNIQUE_DISPLAY_ID);
Sensor proxSensor = setUpProxSensor();
DisplayPowerController2 dpc = new DisplayPowerController2(
mContextSpy, mInjector, mDisplayPowerCallbacksMock, mHandler,
mSensorManagerMock, mDisplayBlankerMock, mLogicalDisplayMock,
mBrightnessTrackerMock, mBrightnessSettingMock, () -> {
});
when(mDisplayPowerStateMock.getScreenState()).thenReturn(Display.STATE_ON);
// send a display power request
DisplayPowerRequest dpr = new DisplayPowerRequest();
dpr.policy = DisplayPowerRequest.POLICY_BRIGHT;
dpr.useProximitySensor = true;
dpc.requestPowerState(dpr, false /* waitForNegativeProximity */);
// Run updatePowerState to start listener for the prox sensor
advanceTime(1);
SensorEventListener listener = getSensorEventListener(proxSensor);
assertNotNull(listener);
listener.onSensorChanged(TestUtils.createSensorEvent(proxSensor, 5 /* lux */));
advanceTime(1);
// two times, one for unfinished business and one for proximity
verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker(
dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID));
verify(mDisplayPowerCallbacksMock).acquireSuspendBlocker(
dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID));
dpc.stop();
advanceTime(1);
// two times, one for unfinished business and one for proximity
verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker(
dpc.getSuspendBlockerUnfinishedBusinessId(DISPLAY_ID));
verify(mDisplayPowerCallbacksMock).releaseSuspendBlocker(
dpc.getSuspendBlockerProxDebounceId(DISPLAY_ID));
}
/**
* Creates a mock and registers it to {@link LocalServices}.
*/
private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
LocalServices.removeServiceForTest(clazz);
LocalServices.addService(clazz, mock);
}
private void advanceTime(long timeMs) {
mClock.fastForward(timeMs);
mTestLooper.dispatchAll();
}
private Sensor setUpProxSensor() throws Exception {
Sensor proxSensor = TestUtils.createSensor(
Sensor.TYPE_PROXIMITY, Sensor.STRING_TYPE_PROXIMITY);
when(mSensorManagerMock.getSensorList(eq(Sensor.TYPE_ALL)))
.thenReturn(List.of(proxSensor));
return proxSensor;
}
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) {
DisplayInfo info = new DisplayInfo();
DisplayDeviceInfo deviceInfo = new DisplayDeviceInfo();
when(mLogicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
when(mLogicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(mDisplayDeviceMock);
when(mLogicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
when(mLogicalDisplayMock.isEnabled()).thenReturn(true);
when(mLogicalDisplayMock.getPhase()).thenReturn(LogicalDisplay.DISPLAY_PHASE_ENABLED);
when(mDisplayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
when(mDisplayDeviceMock.getUniqueId()).thenReturn(uniqueId);
when(mDisplayDeviceMock.getDisplayDeviceConfig()).thenReturn(mDisplayDeviceConfigMock);
when(mDisplayDeviceConfigMock.getProximitySensor()).thenReturn(
new DisplayDeviceConfig.SensorData() {
{
type = Sensor.STRING_TYPE_PROXIMITY;
name = null;
}
});
when(mDisplayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
}
}