diff options
| author | 2024-09-12 14:09:10 +0000 | |
|---|---|---|
| committer | 2024-09-12 14:09:10 +0000 | |
| commit | 87651547e7cac38f7f95db35e6fc59c6d9424fcf (patch) | |
| tree | cdc52cf4e3a4c0a23299da8b7916dc74f7b38aaf | |
| parent | f824197c243a9dc2f059c4cfbe8e9ac29e104c53 (diff) | |
LightSensorController extraction from BrightnessClamperContorller
Also fixed: sensor restart on display changed, sensor registration to comply with ABC
Bug: b/343792639
Test: atest BrightnessClamperControllerTest, atest LightSensorControllerTest
Flag: EXEMPT bugfix, mechanical refactoring
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:2726e78d86b557f3df8573a5a9b11948e46afd0f)
Merged-In: Icddf78defc8fdba83c4d210d12851c7d94adb8b1
Change-Id: Icddf78defc8fdba83c4d210d12851c7d94adb8b1
5 files changed, 465 insertions, 149 deletions
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index ae59d491b8f4..df768dcc564f 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -587,7 +587,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mUniqueDisplayId, mThermalBrightnessThrottlingDataId, logicalDisplay.getPowerThrottlingDataIdLocked(), - mDisplayDeviceConfig), mContext, flags, mSensorManager); + mDisplayDeviceConfig, + mDisplayId), mContext, flags, mSensorManager); // Seed the cached brightness saveBrightnessInfo(getScreenBrightnessSetting()); mAutomaticBrightnessStrategy = @@ -892,7 +893,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call // will call updatePowerState if needed. mBrightnessClamperController.onDisplayChanged( new BrightnessClamperController.DisplayDeviceData(uniqueId, - thermalBrightnessThrottlingDataId, powerThrottlingDataId, config)); + thermalBrightnessThrottlingDataId, powerThrottlingDataId, + config, mDisplayId)); if (changed) { updatePowerState(); diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java index 101ad307f50a..220640270e02 100644 --- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java +++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessClamperController.java @@ -23,23 +23,17 @@ import static com.android.server.display.brightness.clamper.BrightnessClamper.Ty import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.content.res.Resources; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManagerInternal; import android.os.Handler; import android.os.HandlerExecutor; import android.os.PowerManager; -import android.os.SystemClock; import android.provider.DeviceConfig; import android.provider.DeviceConfigInterface; import android.util.IndentingPrintWriter; import android.util.Slog; -import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.server.display.DisplayBrightnessState; import com.android.server.display.DisplayDeviceConfig; @@ -50,30 +44,22 @@ import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.config.SensorData; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.feature.DisplayManagerFlags; -import com.android.server.display.utils.AmbientFilter; -import com.android.server.display.utils.AmbientFilterFactory; -import com.android.server.display.utils.DebugUtils; -import com.android.server.display.utils.SensorUtils; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; /** * Clampers controller, all in DisplayControllerHandler */ public class BrightnessClamperController { private static final String TAG = "BrightnessClamperController"; - // To enable these logs, run: - // 'adb shell setprop persist.log.tag.BrightnessClamperController DEBUG && adb reboot' - private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); - public static final float INVALID_LUX = -1f; private final DeviceConfigParameterProvider mDeviceConfigParameterProvider; private final Handler mHandler; - private final SensorManager mSensorManager; + private final LightSensorController mLightSensorController; + private final ClamperChangeListener mClamperChangeListenerExternal; private final Executor mExecutor; private final List<BrightnessClamper<? super DisplayDeviceData>> mClampers; @@ -85,70 +71,49 @@ public class BrightnessClamperController { private float mCustomAnimationRate = DisplayBrightnessState.CUSTOM_ANIMATION_RATE_NOT_SET; @Nullable private Type mClamperType = null; - private final SensorEventListener mLightSensorListener; - private Sensor mRegisteredLightSensor = null; - private Sensor mLightSensor; - private String mLightSensorType; - private String mLightSensorName; - private AmbientFilter mAmbientFilter; - private final DisplayDeviceConfig mDisplayDeviceConfig; - private final Resources mResources; - private final int mLightSensorRate; - - private final Injector mInjector; + private boolean mClamperApplied = false; + private final LightSensorController.LightSensorListener mLightSensorListener = + new LightSensorController.LightSensorListener() { + @Override + public void onAmbientLuxChange(float lux) { + mModifiers.forEach(mModifier -> mModifier.setAmbientLux(lux)); + } + }; + public BrightnessClamperController(Handler handler, ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context, DisplayManagerFlags flags, SensorManager sensorManager) { - this(null, handler, clamperChangeListener, data, context, flags, sensorManager); + this(new Injector(), handler, clamperChangeListener, data, context, flags, sensorManager); } @VisibleForTesting BrightnessClamperController(Injector injector, Handler handler, ClamperChangeListener clamperChangeListener, DisplayDeviceData data, Context context, DisplayManagerFlags flags, SensorManager sensorManager) { - mInjector = injector == null ? new Injector() : injector; - mDeviceConfigParameterProvider = mInjector.getDeviceConfigParameterProvider(); + mDeviceConfigParameterProvider = injector.getDeviceConfigParameterProvider(); mHandler = handler; - mSensorManager = sensorManager; - mDisplayDeviceConfig = data.mDisplayDeviceConfig; - mLightSensorListener = new SensorEventListener() { - @Override - public void onSensorChanged(SensorEvent event) { - long now = SystemClock.elapsedRealtime(); - mAmbientFilter.addValue(TimeUnit.NANOSECONDS.toMillis(event.timestamp), - event.values[0]); - final float lux = mAmbientFilter.getEstimate(now); - mModifiers.forEach(mModifier -> mModifier.setAmbientLux(lux)); - } - - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - // unused - } - }; + mLightSensorController = injector.getLightSensorController(sensorManager, context, + mLightSensorListener, mHandler); mClamperChangeListenerExternal = clamperChangeListener; mExecutor = new HandlerExecutor(handler); - mResources = context.getResources(); - mLightSensorRate = context.getResources().getInteger( - R.integer.config_autoBrightnessLightSensorRate); Runnable clamperChangeRunnableInternal = this::recalculateBrightnessCap; - ClamperChangeListener clamperChangeListenerInternal = () -> { if (!mHandler.hasCallbacks(clamperChangeRunnableInternal)) { mHandler.post(clamperChangeRunnableInternal); } }; - mClampers = mInjector.getClampers(handler, clamperChangeListenerInternal, data, flags, + mClampers = injector.getClampers(handler, clamperChangeListenerInternal, data, flags, context); - mModifiers = mInjector.getModifiers(flags, context, handler, clamperChangeListener, - data.mDisplayDeviceConfig, mSensorManager); + mModifiers = injector.getModifiers(flags, context, handler, clamperChangeListener, + data.mDisplayDeviceConfig); mOnPropertiesChangedListener = properties -> mClampers.forEach(BrightnessClamper::onDeviceConfigChanged); + mLightSensorController.configure(data.getAmbientLightSensor(), data.getDisplayId()); start(); } @@ -156,7 +121,9 @@ public class BrightnessClamperController { * Should be called when display changed. Forwards the call to individual clampers */ public void onDisplayChanged(DisplayDeviceData data) { + mLightSensorController.configure(data.getAmbientLightSensor(), data.getDisplayId()); mClampers.forEach(clamper -> clamper.onDisplayChanged(data)); + adjustLightSensorSubscription(); } /** @@ -184,9 +151,9 @@ public class BrightnessClamperController { } if (displayState != STATE_ON) { - unregisterSensorListener(); + mLightSensorController.stop(); } else { - maybeRegisterLightSensor(); + adjustLightSensorSubscription(); } for (int i = 0; i < mModifiers.size(); i++) { @@ -231,9 +198,8 @@ public class BrightnessClamperController { writer.println(" mBrightnessCap: " + mBrightnessCap); writer.println(" mClamperType: " + mClamperType); writer.println(" mClamperApplied: " + mClamperApplied); - writer.println(" mLightSensor=" + mLightSensor); - writer.println(" mRegisteredLightSensor=" + mRegisteredLightSensor); IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " "); + mLightSensorController.dump(ipw); mClampers.forEach(clamper -> clamper.dump(ipw)); mModifiers.forEach(modifier -> modifier.dump(ipw)); } @@ -245,6 +211,7 @@ public class BrightnessClamperController { public void stop() { mDeviceConfigParameterProvider.removeOnPropertiesChangedListener( mOnPropertiesChangedListener); + mLightSensorController.stop(); mClampers.forEach(BrightnessClamper::stop); mModifiers.forEach(BrightnessStateModifier::stop); } @@ -281,10 +248,15 @@ public class BrightnessClamperController { if (!mClampers.isEmpty()) { mDeviceConfigParameterProvider.addOnPropertiesChangedListener( mExecutor, mOnPropertiesChangedListener); - reloadLightSensorData(mDisplayDeviceConfig); - mLightSensor = mInjector.getLightSensor( - mSensorManager, mLightSensorType, mLightSensorName); - maybeRegisterLightSensor(); + } + adjustLightSensorSubscription(); + } + + private void adjustLightSensorSubscription() { + if (mModifiers.stream().anyMatch(BrightnessStateModifier::shouldListenToLightSensor)) { + mLightSensorController.restart(); + } else { + mLightSensorController.stop(); } } @@ -323,7 +295,7 @@ public class BrightnessClamperController { List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context, Handler handler, ClamperChangeListener listener, - DisplayDeviceConfig displayDeviceConfig, SensorManager sensorManager) { + DisplayDeviceConfig displayDeviceConfig) { List<BrightnessStateModifier> modifiers = new ArrayList<>(); modifiers.add(new DisplayDimModifier(context)); modifiers.add(new BrightnessLowPowerModeModifier()); @@ -335,11 +307,12 @@ public class BrightnessClamperController { return modifiers; } - Sensor getLightSensor(SensorManager sensorManager, String type, String name) { - return SensorUtils.findSensor(sensorManager, type, - name, Sensor.TYPE_LIGHT); + LightSensorController getLightSensorController(SensorManager sensorManager, + Context context, LightSensorController.LightSensorListener listener, + Handler handler) { + return new LightSensorController(sensorManager, context.getResources(), + listener, handler); } - } /** @@ -354,17 +327,21 @@ public class BrightnessClamperController { private final String mThermalThrottlingDataId; @NonNull private final String mPowerThrottlingDataId; - + @NonNull private final DisplayDeviceConfig mDisplayDeviceConfig; + private final int mDisplayId; + public DisplayDeviceData(@NonNull String uniqueDisplayId, @NonNull String thermalThrottlingDataId, @NonNull String powerThrottlingDataId, - @NonNull DisplayDeviceConfig displayDeviceConfig) { + @NonNull DisplayDeviceConfig displayDeviceConfig, + int displayId) { mUniqueDisplayId = uniqueDisplayId; mThermalThrottlingDataId = thermalThrottlingDataId; mPowerThrottlingDataId = powerThrottlingDataId; mDisplayDeviceConfig = displayDeviceConfig; + mDisplayId = displayId; } @@ -412,55 +389,18 @@ public class BrightnessClamperController { } @NonNull + @Override public SensorData getTempSensor() { return mDisplayDeviceConfig.getTempSensor(); } - } - - private void maybeRegisterLightSensor() { - if (mModifiers.stream().noneMatch(BrightnessStateModifier::shouldListenToLightSensor)) { - return; - } - - if (mRegisteredLightSensor == mLightSensor) { - return; - } - if (mRegisteredLightSensor != null) { - unregisterSensorListener(); - } - - mAmbientFilter = AmbientFilterFactory.createBrightnessFilter(TAG, mResources); - mSensorManager.registerListener(mLightSensorListener, - mLightSensor, mLightSensorRate * 1000, mHandler); - mRegisteredLightSensor = mLightSensor; - - if (DEBUG) { - Slog.d(TAG, "maybeRegisterLightSensor"); - } - } - - private void unregisterSensorListener() { - mSensorManager.unregisterListener(mLightSensorListener); - mRegisteredLightSensor = null; - mModifiers.forEach(mModifier -> mModifier.setAmbientLux(INVALID_LUX)); // set lux to invalid - if (DEBUG) { - Slog.d(TAG, "unregisterSensorListener"); + @NonNull + SensorData getAmbientLightSensor() { + return mDisplayDeviceConfig.getAmbientLightSensor(); } - } - private void reloadLightSensorData(DisplayDeviceConfig displayDeviceConfig) { - // The displayDeviceConfig (ddc) contains display specific preferences. When loaded, - // it naturally falls back to the global config.xml. - if (displayDeviceConfig != null - && displayDeviceConfig.getAmbientLightSensor() != null) { - // This covers both the ddc and the config.xml fallback - mLightSensorType = displayDeviceConfig.getAmbientLightSensor().type; - mLightSensorName = displayDeviceConfig.getAmbientLightSensor().name; - } else if (mLightSensorName == null && mLightSensorType == null) { - mLightSensorType = mResources.getString( - com.android.internal.R.string.config_displayLightSensorType); - mLightSensorName = ""; + int getDisplayId() { + return mDisplayId; } } } diff --git a/services/core/java/com/android/server/display/brightness/clamper/LightSensorController.java b/services/core/java/com/android/server/display/brightness/clamper/LightSensorController.java new file mode 100644 index 000000000000..d89dd28c4a89 --- /dev/null +++ b/services/core/java/com/android/server/display/brightness/clamper/LightSensorController.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2024 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.brightness.clamper; + +import android.annotation.Nullable; +import android.content.res.Resources; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Handler; +import android.os.SystemClock; +import android.util.Slog; +import android.view.Display; + +import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.display.config.SensorData; +import com.android.server.display.utils.AmbientFilter; +import com.android.server.display.utils.AmbientFilterFactory; +import com.android.server.display.utils.DebugUtils; +import com.android.server.display.utils.SensorUtils; + +import java.io.PrintWriter; +import java.util.concurrent.TimeUnit; + +/** + * Manages light sensor subscription and notifies its listener about ambient lux changes + */ +public class LightSensorController { + private static final String TAG = "LightSensorController"; + + // To enable these logs, run: + // 'adb shell setprop persist.log.tag.LightSensorController DEBUG && adb reboot' + private static final boolean DEBUG = DebugUtils.isDebuggable(TAG); + static final float INVALID_LUX = -1f; + + private final SensorManager mSensorManager; + private final LightSensorListener mLightSensorListener; + private final Handler mHandler; + private final Injector mInjector; + private final AmbientFilter mAmbientFilter; + + private Sensor mLightSensor; + private Sensor mRegisteredLightSensor = null; + private final int mLightSensorRate; + + private final SensorEventListener mLightSensorEventListener = new SensorEventListener() { + @Override + public void onSensorChanged(SensorEvent event) { + long now = mInjector.getTime(); + mAmbientFilter.addValue(TimeUnit.NANOSECONDS.toMillis(event.timestamp), + event.values[0]); + final float lux = mAmbientFilter.getEstimate(now); + mLightSensorListener.onAmbientLuxChange(lux); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + // unused + } + }; + + LightSensorController(SensorManager sensorManager, Resources resources, + LightSensorListener listener, Handler handler) { + this(sensorManager, resources, listener, handler, new Injector()); + } + + @VisibleForTesting + LightSensorController(SensorManager sensorManager, Resources resources, + LightSensorListener listener, Handler handler, Injector injector) { + mSensorManager = sensorManager; + mLightSensorRate = injector.getLightSensorRate(resources); + mAmbientFilter = injector.getAmbientFilter(resources); + mLightSensorListener = listener; + mHandler = handler; + mInjector = injector; + } + + void restart() { + if (mRegisteredLightSensor == mLightSensor) { + return; + } + if (mRegisteredLightSensor != null) { + stop(); + } + if (mLightSensor == null) { + return; + } + + mSensorManager.registerListener(mLightSensorEventListener, + mLightSensor, mLightSensorRate * 1000, mHandler); + mRegisteredLightSensor = mLightSensor; + + if (DEBUG) { + Slog.d(TAG, "restart"); + } + } + + void stop() { + if (mRegisteredLightSensor == null) { + return; + } + mSensorManager.unregisterListener(mLightSensorEventListener); + mRegisteredLightSensor = null; + mAmbientFilter.clear(); + mLightSensorListener.onAmbientLuxChange(INVALID_LUX); + if (DEBUG) { + Slog.d(TAG, "stop"); + } + } + + void configure(SensorData sensorData, int displayId) { + final int fallbackType = displayId == Display.DEFAULT_DISPLAY + ? Sensor.TYPE_LIGHT : SensorUtils.NO_FALLBACK; + mLightSensor = mInjector.getLightSensor(mSensorManager, sensorData, fallbackType); + } + + void dump(PrintWriter writer) { + writer.println("LightSensorController"); + writer.println(" mLightSensor=" + mLightSensor); + writer.println(" mRegisteredLightSensor=" + mRegisteredLightSensor); + } + + static class Injector { + @Nullable + Sensor getLightSensor(SensorManager sensorManager, SensorData sensorData, + int fallbackType) { + return SensorUtils.findSensor(sensorManager, sensorData, fallbackType); + } + + AmbientFilter getAmbientFilter(Resources resources) { + return AmbientFilterFactory.createBrightnessFilter(TAG, resources); + } + + int getLightSensorRate(Resources resources) { + return resources.getInteger(R.integer.config_autoBrightnessLightSensorRate); + } + + // should be consistent with SensorEvent.timestamp + long getTime() { + return SystemClock.elapsedRealtime(); + } + } + + interface LightSensorListener { + void onAmbientLuxChange(float ambientLux); + } +} diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java index 69043f5704de..e982153acbd1 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessClamperControllerTest.java @@ -16,19 +16,19 @@ package com.android.server.display.brightness.clamper; +import static android.view.Display.STATE_OFF; import static android.view.Display.STATE_ON; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.hardware.Sensor; -import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManagerInternal; @@ -40,12 +40,10 @@ import android.testing.TestableContext; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.internal.util.test.FakeSettingsProvider; -import com.android.internal.util.test.FakeSettingsProviderRule; import com.android.server.display.DisplayBrightnessState; import com.android.server.display.DisplayDeviceConfig; -import com.android.server.display.TestUtils; import com.android.server.display.brightness.BrightnessReason; +import com.android.server.display.config.SensorData; import com.android.server.display.feature.DeviceConfigParameterProvider; import com.android.server.display.feature.DisplayManagerFlags; import com.android.server.testutils.OffsettableClock; @@ -63,6 +61,7 @@ import java.util.List; @SmallTest public class BrightnessClamperControllerTest { private static final float FLOAT_TOLERANCE = 0.001f; + private static final int DISPLAY_ID = 2; private final OffsettableClock mClock = new OffsettableClock(); private final TestHandler mTestHandler = new TestHandler(null, mClock); @@ -78,8 +77,12 @@ public class BrightnessClamperControllerTest { @Mock private BrightnessClamperController.DisplayDeviceData mMockDisplayDeviceData; @Mock + private SensorData mMockSensorData; + @Mock private DeviceConfigParameterProvider mMockDeviceConfigParameterProvider; @Mock + private LightSensorController mMockLightSensorController; + @Mock private BrightnessClamper<BrightnessClamperController.DisplayDeviceData> mMockClamper; @Mock private DisplayManagerFlags mFlags; @@ -88,23 +91,17 @@ public class BrightnessClamperControllerTest { @Mock private DisplayManagerInternal.DisplayPowerRequest mMockRequest; - Sensor mLightSensor; - @Mock private DeviceConfig.Properties mMockProperties; private BrightnessClamperController mClamperController; private TestInjector mTestInjector; - @Rule - public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor"); mTestInjector = new TestInjector(List.of(mMockClamper), List.of(mMockModifier)); - when(mSensorManager.getDefaultSensor(anyInt())).thenReturn(mLightSensor); - when(mMockModifier.shouldListenToLightSensor()).thenReturn(true); + when(mMockDisplayDeviceData.getDisplayId()).thenReturn(DISPLAY_ID); + when(mMockDisplayDeviceData.getAmbientLightSensor()).thenReturn(mMockSensorData); mClamperController = createBrightnessClamperController(); } @@ -115,6 +112,25 @@ public class BrightnessClamperControllerTest { } @Test + public void testConstructor_ConfiguresLightSensorController() { + verify(mMockLightSensorController).configure(mMockSensorData, DISPLAY_ID); + } + + @Test + public void testConstructor_doesNotStartsLightSensorController() { + verify(mMockLightSensorController, never()).restart(); + } + + @Test + public void testConstructor_startsLightSensorController() { + when(mMockModifier.shouldListenToLightSensor()).thenReturn(true); + + mClamperController = createBrightnessClamperController(); + + verify(mMockLightSensorController).restart(); + } + + @Test public void testStop_RemovesOnPropertiesChangeListener() { ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener> captor = ArgumentCaptor.forClass( DeviceConfig.OnPropertiesChangedListener.class); @@ -152,6 +168,21 @@ public class BrightnessClamperControllerTest { } @Test + public void testOnDisplayChanged_doesNotRestartLightSensor() { + mClamperController.onDisplayChanged(mMockDisplayDeviceData); + + verify(mMockLightSensorController, never()).restart(); + } + + @Test + public void testOnDisplayChanged_restartsLightSensor() { + when(mMockModifier.shouldListenToLightSensor()).thenReturn(true); + mClamperController.onDisplayChanged(mMockDisplayDeviceData); + + verify(mMockLightSensorController).restart(); + } + + @Test public void testClamp_AppliesModifier() { float initialBrightness = 0.2f; boolean initialSlowChange = true; @@ -161,6 +192,26 @@ public class BrightnessClamperControllerTest { } @Test + public void testClamp_restartsLightSensor() { + float initialBrightness = 0.2f; + boolean initialSlowChange = true; + when(mMockModifier.shouldListenToLightSensor()).thenReturn(true); + mClamperController.clamp(mMockRequest, initialBrightness, initialSlowChange, STATE_ON); + + verify(mMockLightSensorController).restart(); + } + + @Test + public void testClamp_stopsLightSensor() { + float initialBrightness = 0.2f; + boolean initialSlowChange = true; + clearInvocations(mMockLightSensorController); + mClamperController.clamp(mMockRequest, initialBrightness, initialSlowChange, STATE_OFF); + + verify(mMockLightSensorController).stop(); + } + + @Test public void testClamp_inactiveClamperNotApplied() { float initialBrightness = 0.8f; boolean initialSlowChange = true; @@ -260,33 +311,17 @@ public class BrightnessClamperControllerTest { } @Test - public void testAmbientLuxChanges() throws Exception { - ArgumentCaptor<SensorEventListener> listenerCaptor = ArgumentCaptor.forClass( - SensorEventListener.class); - - verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor), - anyInt(), any(Handler.class)); - SensorEventListener listener = listenerCaptor.getValue(); - - when(mSensorManager.getSensorList(eq(Sensor.TYPE_ALL))).thenReturn(List.of(mLightSensor)); - - float initialBrightness = 0.8f; - boolean initialSlowChange = true; - - DisplayBrightnessState state = mClamperController.clamp(mMockRequest, initialBrightness, - initialSlowChange, STATE_ON); - assertEquals(initialBrightness, state.getBrightness(), FLOAT_TOLERANCE); + public void testAmbientLuxChanges() { + mTestInjector.mCapturedLightSensorListener.onAmbientLuxChange(50); - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 50, mClock.now())); verify(mMockModifier).setAmbientLux(50); - - listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 300, mClock.now())); - verify(mMockModifier).setAmbientLux(300); } @Test public void testStop() { + clearInvocations(mMockLightSensorController); mClamperController.stop(); + verify(mMockLightSensorController).stop(); verify(mMockModifier).stop(); verify(mMockClamper).stop(); } @@ -303,6 +338,7 @@ public class BrightnessClamperControllerTest { private final List<BrightnessStateModifier> mModifiers; private BrightnessClamperController.ClamperChangeListener mCapturedChangeListener; + private LightSensorController.LightSensorListener mCapturedLightSensorListener; private TestInjector( List<BrightnessClamper<? super BrightnessClamperController.DisplayDeviceData>> @@ -330,8 +366,15 @@ public class BrightnessClamperControllerTest { @Override List<BrightnessStateModifier> getModifiers(DisplayManagerFlags flags, Context context, Handler handler, BrightnessClamperController.ClamperChangeListener listener, - DisplayDeviceConfig displayDeviceConfig, SensorManager sensorManager) { + DisplayDeviceConfig displayDeviceConfig) { return mModifiers; } + + @Override + LightSensorController getLightSensorController(SensorManager sensorManager, Context context, + LightSensorController.LightSensorListener listener, Handler handler) { + mCapturedLightSensorListener = listener; + return mMockLightSensorController; + } } } diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/LightSensorControllerTest.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/LightSensorControllerTest.kt new file mode 100644 index 000000000000..b742d021f2e9 --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/LightSensorControllerTest.kt @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2023 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.brightness.clamper + +import android.content.res.Resources +import android.hardware.Sensor +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import android.os.Handler +import androidx.test.filters.SmallTest +import com.android.server.display.TestUtils +import com.android.server.display.brightness.clamper.LightSensorController.Injector +import com.android.server.display.brightness.clamper.LightSensorController.LightSensorListener +import com.android.server.display.config.SensorData +import com.android.server.display.utils.AmbientFilter +import org.junit.Before +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.eq +import org.mockito.kotlin.inOrder +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyNoMoreInteractions +import org.mockito.kotlin.whenever + +private const val LIGHT_SENSOR_RATE: Int = 10 +private const val DISPLAY_ID: Int = 3 +private const val NOW: Long = 3_000 + +@SmallTest +class LightSensorControllerTest { + + private val mockSensorManager: SensorManager = mock() + private val mockResources: Resources = mock() + private val mockLightSensorListener: LightSensorListener = mock() + private val mockHandler: Handler = mock() + private val mockAmbientFilter: AmbientFilter = mock() + + private val testInjector = TestInjector() + private val dummySensorData = SensorData() + + private lateinit var controller: LightSensorController + + @Before + fun setUp() { + controller = LightSensorController(mockSensorManager, mockResources, + mockLightSensorListener, mockHandler, testInjector) + } + + fun `does not register light sensor if is not configured`() { + controller.restart() + + verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener) + } + + fun `does not register light sensor if missing`() { + controller.configure(dummySensorData, DISPLAY_ID) + controller.restart() + + verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener) + } + + fun `register light sensor if configured and present`() { + testInjector.lightSensor = TestUtils + .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT) + controller.configure(dummySensorData, DISPLAY_ID) + controller.restart() + + verify(mockSensorManager).registerListener(any(), + testInjector.lightSensor, LIGHT_SENSOR_RATE * 1000, mockHandler) + verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener) + } + + fun `register light sensor once if not changed`() { + testInjector.lightSensor = TestUtils + .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT) + controller.configure(dummySensorData, DISPLAY_ID) + + controller.restart() + controller.restart() + + verify(mockSensorManager).registerListener(any(), + testInjector.lightSensor, LIGHT_SENSOR_RATE * 1000, mockHandler) + verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener) + } + + fun `register new light sensor and unregister old if changed`() { + val lightSensor1 = TestUtils + .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT) + testInjector.lightSensor = lightSensor1 + controller.configure(dummySensorData, DISPLAY_ID) + controller.restart() + + val lightSensor2 = TestUtils + .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT) + testInjector.lightSensor = lightSensor2 + controller.configure(dummySensorData, DISPLAY_ID) + controller.restart() + + inOrder { + verify(mockSensorManager).registerListener(any(), + lightSensor1, LIGHT_SENSOR_RATE * 1000, mockHandler) + verify(mockSensorManager).unregisterListener(any<SensorEventListener>()) + verify(mockAmbientFilter).clear() + verify(mockLightSensorListener).onAmbientLuxChange(LightSensorController.INVALID_LUX) + verify(mockSensorManager).registerListener(any(), + lightSensor2, LIGHT_SENSOR_RATE * 1000, mockHandler) + } + verifyNoMoreInteractions(mockSensorManager, mockAmbientFilter, mockLightSensorListener) + } + + fun `notifies listener on ambient lux change`() { + val expectedLux = 40f + val eventLux = 50 + val eventTime = 60L + whenever(mockAmbientFilter.getEstimate(NOW)).thenReturn(expectedLux) + val listenerCaptor = argumentCaptor<SensorEventListener>() + testInjector.lightSensor = TestUtils + .createSensor(Sensor.TYPE_LIGHT, Sensor.STRING_TYPE_LIGHT) + controller.configure(dummySensorData, DISPLAY_ID) + controller.restart() + verify(mockSensorManager).registerListener(listenerCaptor.capture(), + eq(testInjector.lightSensor), eq(LIGHT_SENSOR_RATE * 1000), eq(mockHandler)) + + val listener = listenerCaptor.lastValue + listener.onSensorChanged(TestUtils.createSensorEvent(testInjector.lightSensor, + eventLux, eventTime * 1_000_000)) + + inOrder { + verify(mockAmbientFilter).addValue(eventTime, eventLux.toFloat()) + verify(mockLightSensorListener).onAmbientLuxChange(expectedLux) + } + } + + private inner class TestInjector : Injector() { + var lightSensor: Sensor? = null + override fun getLightSensor(sensorManager: SensorManager?, + sensorData: SensorData?, fallbackType: Int): Sensor? { + return lightSensor + } + + override fun getLightSensorRate(resources: Resources?): Int { + return LIGHT_SENSOR_RATE + } + + override fun getAmbientFilter(resources: Resources?): AmbientFilter { + return mockAmbientFilter + } + + override fun getTime(): Long { + return NOW + } + } +}
\ No newline at end of file |