Merge "Clamp brightness thresholds to the maximum brightness." into qt-qpr1-dev
This commit is contained in:
@@ -41,6 +41,7 @@ import android.util.MathUtils;
|
|||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.TimeUtils;
|
import android.util.TimeUtils;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.os.BackgroundThread;
|
import com.android.internal.os.BackgroundThread;
|
||||||
import com.android.server.EventLogTags;
|
import com.android.server.EventLogTags;
|
||||||
|
|
||||||
@@ -215,7 +216,9 @@ class AutomaticBrightnessController {
|
|||||||
private IActivityTaskManager mActivityTaskManager;
|
private IActivityTaskManager mActivityTaskManager;
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
|
|
||||||
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
|
private final Injector mInjector;
|
||||||
|
|
||||||
|
AutomaticBrightnessController(Callbacks callbacks, Looper looper,
|
||||||
SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
|
SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
|
||||||
int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
|
int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
|
||||||
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
|
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
|
||||||
@@ -223,6 +226,24 @@ class AutomaticBrightnessController {
|
|||||||
HysteresisLevels ambientBrightnessThresholds,
|
HysteresisLevels ambientBrightnessThresholds,
|
||||||
HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
|
HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
|
||||||
PackageManager packageManager) {
|
PackageManager packageManager) {
|
||||||
|
this(new Injector(), callbacks, looper, sensorManager, lightSensor, mapper,
|
||||||
|
lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
|
||||||
|
lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
|
||||||
|
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
|
||||||
|
ambientBrightnessThresholds, screenBrightnessThresholds, shortTermModelTimeout,
|
||||||
|
packageManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper,
|
||||||
|
SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
|
||||||
|
int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
|
||||||
|
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
|
||||||
|
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
|
||||||
|
HysteresisLevels ambientBrightnessThresholds,
|
||||||
|
HysteresisLevels screenBrightnessThresholds, long shortTermModelTimeout,
|
||||||
|
PackageManager packageManager) {
|
||||||
|
mInjector = injector;
|
||||||
mCallbacks = callbacks;
|
mCallbacks = callbacks;
|
||||||
mSensorManager = sensorManager;
|
mSensorManager = sensorManager;
|
||||||
mBrightnessMapper = mapper;
|
mBrightnessMapper = mapper;
|
||||||
@@ -725,8 +746,8 @@ class AutomaticBrightnessController {
|
|||||||
float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
|
float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
|
||||||
mForegroundAppCategory);
|
mForegroundAppCategory);
|
||||||
|
|
||||||
int newScreenAutoBrightness =
|
int newScreenAutoBrightness = Math.round(clampScreenBrightness(
|
||||||
clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON));
|
value * PowerManager.BRIGHTNESS_ON));
|
||||||
|
|
||||||
// If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
|
// If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
|
||||||
// in which case we ignore the new screen brightness if it doesn't differ enough from the
|
// in which case we ignore the new screen brightness if it doesn't differ enough from the
|
||||||
@@ -750,10 +771,10 @@ class AutomaticBrightnessController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mScreenAutoBrightness = newScreenAutoBrightness;
|
mScreenAutoBrightness = newScreenAutoBrightness;
|
||||||
mScreenBrighteningThreshold =
|
mScreenBrighteningThreshold = clampScreenBrightness(
|
||||||
mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness);
|
mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
|
||||||
mScreenDarkeningThreshold =
|
mScreenDarkeningThreshold = clampScreenBrightness(
|
||||||
mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness);
|
mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
|
||||||
|
|
||||||
if (sendUpdate) {
|
if (sendUpdate) {
|
||||||
mCallbacks.updateBrightness();
|
mCallbacks.updateBrightness();
|
||||||
@@ -761,7 +782,7 @@ class AutomaticBrightnessController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int clampScreenBrightness(int value) {
|
private float clampScreenBrightness(float value) {
|
||||||
return MathUtils.constrain(value,
|
return MathUtils.constrain(value,
|
||||||
mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
|
mScreenBrightnessRangeMinimum, mScreenBrightnessRangeMaximum);
|
||||||
}
|
}
|
||||||
@@ -839,7 +860,7 @@ class AutomaticBrightnessController {
|
|||||||
}
|
}
|
||||||
// The ActivityTaskManager's lock tends to get contended, so this is done in a background
|
// The ActivityTaskManager's lock tends to get contended, so this is done in a background
|
||||||
// thread and applied via this thread's handler synchronously.
|
// thread and applied via this thread's handler synchronously.
|
||||||
BackgroundThread.getHandler().post(new Runnable() {
|
mInjector.getBackgroundThreadHandler().post(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// The foreground app is the top activity of the focused tasks stack.
|
// The foreground app is the top activity of the focused tasks stack.
|
||||||
@@ -965,6 +986,9 @@ class AutomaticBrightnessController {
|
|||||||
private int mCount;
|
private int mCount;
|
||||||
|
|
||||||
public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
|
public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
|
||||||
|
if (lightSensorRate <= 0) {
|
||||||
|
throw new IllegalArgumentException("lightSensorRate must be above 0");
|
||||||
|
}
|
||||||
mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
|
mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
|
||||||
mRingLux = new float[mCapacity];
|
mRingLux = new float[mCapacity];
|
||||||
mRingTime = new long[mCapacity];
|
mRingTime = new long[mCapacity];
|
||||||
@@ -1076,4 +1100,10 @@ class AutomaticBrightnessController {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Injector {
|
||||||
|
public Handler getBackgroundThreadHandler() {
|
||||||
|
return BackgroundThread.getHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,13 +18,16 @@ package com.android.server.display;
|
|||||||
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class for handling access to illuminance hysteresis level values.
|
* A helper class for handling access to illuminance hysteresis level values.
|
||||||
*/
|
*/
|
||||||
final class HysteresisLevels {
|
@VisibleForTesting
|
||||||
|
public class HysteresisLevels {
|
||||||
private static final String TAG = "HysteresisLevels";
|
private static final String TAG = "HysteresisLevels";
|
||||||
|
|
||||||
// Default hysteresis constraints for brightening or darkening.
|
// Default hysteresis constraints for brightening or darkening.
|
||||||
@@ -60,7 +63,7 @@ final class HysteresisLevels {
|
|||||||
/**
|
/**
|
||||||
* Return the brightening hysteresis threshold for the given value level.
|
* Return the brightening hysteresis threshold for the given value level.
|
||||||
*/
|
*/
|
||||||
float getBrighteningThreshold(float value) {
|
public float getBrighteningThreshold(float value) {
|
||||||
float brightConstant = getReferenceLevel(value, mBrighteningThresholds);
|
float brightConstant = getReferenceLevel(value, mBrighteningThresholds);
|
||||||
float brightThreshold = value * (1.0f + brightConstant);
|
float brightThreshold = value * (1.0f + brightConstant);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@@ -73,7 +76,7 @@ final class HysteresisLevels {
|
|||||||
/**
|
/**
|
||||||
* Return the darkening hysteresis threshold for the given value level.
|
* Return the darkening hysteresis threshold for the given value level.
|
||||||
*/
|
*/
|
||||||
float getDarkeningThreshold(float value) {
|
public float getDarkeningThreshold(float value) {
|
||||||
float darkConstant = getReferenceLevel(value, mDarkeningThresholds);
|
float darkConstant = getReferenceLevel(value, mDarkeningThresholds);
|
||||||
float darkThreshold = value * (1.0f - darkConstant);
|
float darkThreshold = value * (1.0f - darkConstant);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.any;
|
||||||
|
import static org.mockito.Mockito.anyFloat;
|
||||||
|
import static org.mockito.Mockito.anyInt;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEventListener;
|
||||||
|
import android.hardware.SensorManager;
|
||||||
|
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class AutomaticBrightnessControllerTest {
|
||||||
|
|
||||||
|
private static final int BRIGHTNESS_MIN = 1;
|
||||||
|
private static final int BRIGHTNESS_MAX = 255;
|
||||||
|
private static final int LIGHT_SENSOR_RATE = 20;
|
||||||
|
private static final int INITIAL_LIGHT_SENSOR_RATE = 20;
|
||||||
|
private static final int BRIGHTENING_LIGHT_DEBOUNCE_CONFIG = 0;
|
||||||
|
private static final int DARKENING_LIGHT_DEBOUNCE_CONFIG = 0;
|
||||||
|
private static final int SHORT_TERM_MODEL_TIMEOUT = 0;
|
||||||
|
private static final float DOZE_SCALE_FACTOR = 0.0f;
|
||||||
|
private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
@Mock SensorManager mSensorManager;
|
||||||
|
@Mock BrightnessMappingStrategy mBrightnessMappingStrategy;
|
||||||
|
@Mock HysteresisLevels mAmbientBrightnessThresholds;
|
||||||
|
@Mock HysteresisLevels mScreenBrightnessThresholds;
|
||||||
|
@Mock PackageManager mPackageManager;
|
||||||
|
@Mock Handler mNoopHandler;
|
||||||
|
|
||||||
|
private static final int LIGHT_SENSOR_WARMUP_TIME = 0;
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
mContext = InstrumentationRegistry.getContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AutomaticBrightnessController setupController(Sensor lightSensor) {
|
||||||
|
AutomaticBrightnessController controller = new AutomaticBrightnessController(
|
||||||
|
new AutomaticBrightnessController.Injector() {
|
||||||
|
@Override
|
||||||
|
public Handler getBackgroundThreadHandler() {
|
||||||
|
return mNoopHandler;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
() -> { }, mContext.getMainLooper(), mSensorManager, lightSensor,
|
||||||
|
mBrightnessMappingStrategy, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN,
|
||||||
|
BRIGHTNESS_MAX, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE, INITIAL_LIGHT_SENSOR_RATE,
|
||||||
|
BRIGHTENING_LIGHT_DEBOUNCE_CONFIG, DARKENING_LIGHT_DEBOUNCE_CONFIG,
|
||||||
|
RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG, mAmbientBrightnessThresholds,
|
||||||
|
mScreenBrightnessThresholds, SHORT_TERM_MODEL_TIMEOUT, mPackageManager);
|
||||||
|
controller.setLoggingEnabled(true);
|
||||||
|
|
||||||
|
// Configure the brightness controller and grab an instance of the sensor listener,
|
||||||
|
// through which we can deliver fake (for test) sensor values.
|
||||||
|
controller.configure(true /* enable */, null /* configuration */,
|
||||||
|
0 /* brightness */, false /* userChangedBrightness */, 0 /* adjustment */,
|
||||||
|
false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoHysteresisAtMinBrightness() throws Exception {
|
||||||
|
Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
|
||||||
|
AutomaticBrightnessController controller = setupController(lightSensor);
|
||||||
|
|
||||||
|
ArgumentCaptor<SensorEventListener> listenerCaptor =
|
||||||
|
ArgumentCaptor.forClass(SensorEventListener.class);
|
||||||
|
verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
|
||||||
|
eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
|
||||||
|
SensorEventListener listener = listenerCaptor.getValue();
|
||||||
|
|
||||||
|
// Set up system to return 5 as a brightness value
|
||||||
|
float lux1 = 100.0f;
|
||||||
|
float normalizedBrightness1 = 0.02f;
|
||||||
|
when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1))
|
||||||
|
.thenReturn(lux1);
|
||||||
|
when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1))
|
||||||
|
.thenReturn(lux1);
|
||||||
|
when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt()))
|
||||||
|
.thenReturn(normalizedBrightness1);
|
||||||
|
|
||||||
|
// This is the important bit: When the new brightness is set, make sure the new
|
||||||
|
// brightening threshold is beyond the maximum brightness value...so that we can test that
|
||||||
|
// our threshold clamping works.
|
||||||
|
when(mScreenBrightnessThresholds.getBrighteningThreshold(5)).thenReturn(1.0f);
|
||||||
|
|
||||||
|
// Send new sensor value and verify
|
||||||
|
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux1));
|
||||||
|
assertEquals(5, controller.getAutomaticScreenBrightness());
|
||||||
|
|
||||||
|
|
||||||
|
// Set up system to return 255 as a brightness value
|
||||||
|
float lux2 = 10.0f;
|
||||||
|
float normalizedBrightness2 = 0.0f;
|
||||||
|
when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2))
|
||||||
|
.thenReturn(lux2);
|
||||||
|
when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2))
|
||||||
|
.thenReturn(lux2);
|
||||||
|
when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt()))
|
||||||
|
.thenReturn(normalizedBrightness2);
|
||||||
|
|
||||||
|
// Send new sensor value and verify
|
||||||
|
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux2));
|
||||||
|
assertEquals(1, controller.getAutomaticScreenBrightness());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoHysteresisAtMaxBrightness() throws Exception {
|
||||||
|
Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
|
||||||
|
AutomaticBrightnessController controller = setupController(lightSensor);
|
||||||
|
|
||||||
|
ArgumentCaptor<SensorEventListener> listenerCaptor =
|
||||||
|
ArgumentCaptor.forClass(SensorEventListener.class);
|
||||||
|
verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
|
||||||
|
eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
|
||||||
|
SensorEventListener listener = listenerCaptor.getValue();
|
||||||
|
|
||||||
|
// Set up system to return 250 as a brightness value
|
||||||
|
float lux1 = 100.0f;
|
||||||
|
float normalizedBrightness1 = 0.98f;
|
||||||
|
when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux1))
|
||||||
|
.thenReturn(lux1);
|
||||||
|
when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux1))
|
||||||
|
.thenReturn(lux1);
|
||||||
|
when(mBrightnessMappingStrategy.getBrightness(eq(lux1), eq(null), anyInt()))
|
||||||
|
.thenReturn(normalizedBrightness1);
|
||||||
|
|
||||||
|
// This is the important bit: When the new brightness is set, make sure the new
|
||||||
|
// brightening threshold is beyond the maximum brightness value...so that we can test that
|
||||||
|
// our threshold clamping works.
|
||||||
|
when(mScreenBrightnessThresholds.getBrighteningThreshold(250)).thenReturn(260.0f);
|
||||||
|
|
||||||
|
// Send new sensor value and verify
|
||||||
|
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux1));
|
||||||
|
assertEquals(250, controller.getAutomaticScreenBrightness());
|
||||||
|
|
||||||
|
|
||||||
|
// Set up system to return 255 as a brightness value
|
||||||
|
float lux2 = 110.0f;
|
||||||
|
float normalizedBrightness2 = 1.0f;
|
||||||
|
when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux2))
|
||||||
|
.thenReturn(lux2);
|
||||||
|
when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux2))
|
||||||
|
.thenReturn(lux2);
|
||||||
|
when(mBrightnessMappingStrategy.getBrightness(anyFloat(), eq(null), anyInt()))
|
||||||
|
.thenReturn(normalizedBrightness2);
|
||||||
|
|
||||||
|
// Send new sensor value and verify
|
||||||
|
listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, (int) lux2));
|
||||||
|
assertEquals(255, controller.getAutomaticScreenBrightness());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.android.server.display;
|
package com.android.server.display;
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 android.hardware.Sensor;
|
||||||
|
import android.hardware.SensorEvent;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public final class TestUtils {
|
||||||
|
|
||||||
|
public static SensorEvent createSensorEvent(Sensor sensor, int lux) throws Exception {
|
||||||
|
final Constructor<SensorEvent> constructor =
|
||||||
|
SensorEvent.class.getDeclaredConstructor(int.class);
|
||||||
|
constructor.setAccessible(true);
|
||||||
|
final SensorEvent event = constructor.newInstance(1);
|
||||||
|
event.sensor = sensor;
|
||||||
|
event.values[0] = lux;
|
||||||
|
event.timestamp = SystemClock.elapsedRealtimeNanos();
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void setSensorType(Sensor sensor, int type, String strType) throws Exception {
|
||||||
|
Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
|
||||||
|
setter.setAccessible(true);
|
||||||
|
setter.invoke(sensor, type);
|
||||||
|
if (strType != null) {
|
||||||
|
Field f = sensor.getClass().getDeclaredField("mStringType");
|
||||||
|
f.setAccessible(true);
|
||||||
|
f.set(sensor, strType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Sensor createSensor(int type, String strType) throws Exception {
|
||||||
|
Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
|
||||||
|
constr.setAccessible(true);
|
||||||
|
Sensor sensor = constr.newInstance();
|
||||||
|
setSensorType(sensor, type, strType);
|
||||||
|
return sensor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,29 +16,19 @@
|
|||||||
|
|
||||||
package com.android.server.display.whitebalance;
|
package com.android.server.display.whitebalance;
|
||||||
|
|
||||||
import com.android.internal.R;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
import static org.mockito.Mockito.doAnswer;
|
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyLong;
|
import static org.mockito.Matchers.anyLong;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import org.mockito.stubbing.Answer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import static org.mockito.Mockito.mock;
|
||||||
import org.mockito.Mock;
|
import static org.mockito.Mockito.spy;
|
||||||
import org.mockito.MockitoAnnotations;
|
import static org.mockito.Mockito.when;
|
||||||
import org.mockito.Spy;
|
|
||||||
|
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.hardware.Sensor;
|
import android.hardware.Sensor;
|
||||||
import android.hardware.SensorEvent;
|
|
||||||
import android.hardware.SensorEventListener;
|
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -46,15 +36,21 @@ import android.util.TypedValue;
|
|||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
import com.android.server.display.TestUtils;
|
||||||
|
import com.android.server.display.whitebalance.AmbientFilter;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
@@ -80,8 +76,8 @@ public final class AmbientLuxTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mLightSensor = createSensor(Sensor.TYPE_LIGHT, null);
|
mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, null);
|
||||||
mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
|
mAmbientColorSensor = TestUtils.createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
|
||||||
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
||||||
mResourcesSpy = spy(mContextSpy.getResources());
|
mResourcesSpy = spy(mContextSpy.getResources());
|
||||||
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
|
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
|
||||||
@@ -460,25 +456,6 @@ public final class AmbientLuxTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSensorType(Sensor sensor, int type, String strType) throws Exception {
|
|
||||||
Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
|
|
||||||
setter.setAccessible(true);
|
|
||||||
setter.invoke(sensor, type);
|
|
||||||
if (strType != null) {
|
|
||||||
Field f = sensor.getClass().getDeclaredField("mStringType");
|
|
||||||
f.setAccessible(true);
|
|
||||||
f.set(sensor, strType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Sensor createSensor(int type, String strType) throws Exception {
|
|
||||||
Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
|
|
||||||
constr.setAccessible(true);
|
|
||||||
Sensor sensor = constr.newInstance();
|
|
||||||
setSensorType(sensor, type, strType);
|
|
||||||
return sensor;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TypedArray createTypedArray() throws Exception {
|
private TypedArray createTypedArray() throws Exception {
|
||||||
TypedArray mockArray = mock(TypedArray.class);
|
TypedArray mockArray = mock(TypedArray.class);
|
||||||
return mockArray;
|
return mockArray;
|
||||||
|
|||||||
@@ -28,15 +28,14 @@ import static org.mockito.Mockito.when;
|
|||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.hardware.Sensor;
|
import android.hardware.Sensor;
|
||||||
import android.hardware.SensorEvent;
|
|
||||||
import android.hardware.SensorEventListener;
|
import android.hardware.SensorEventListener;
|
||||||
import android.hardware.SensorManager;
|
import android.hardware.SensorManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.SystemClock;
|
|
||||||
|
|
||||||
import androidx.test.InstrumentationRegistry;
|
import androidx.test.InstrumentationRegistry;
|
||||||
|
|
||||||
|
import com.android.server.display.TestUtils;
|
||||||
import com.android.server.display.whitebalance.AmbientSensor.AmbientBrightnessSensor;
|
import com.android.server.display.whitebalance.AmbientSensor.AmbientBrightnessSensor;
|
||||||
import com.android.server.display.whitebalance.AmbientSensor.AmbientColorTemperatureSensor;
|
import com.android.server.display.whitebalance.AmbientSensor.AmbientColorTemperatureSensor;
|
||||||
|
|
||||||
@@ -50,9 +49,6 @@ import org.mockito.ArgumentCaptor;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -73,8 +69,8 @@ public final class AmbientSensorTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mLightSensor = createSensor(Sensor.TYPE_LIGHT, null);
|
mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, null);
|
||||||
mAmbientColorSensor = createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
|
mAmbientColorSensor = TestUtils.createSensor(AMBIENT_COLOR_TYPE, AMBIENT_COLOR_TYPE_STR);
|
||||||
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
|
||||||
mResourcesSpy = spy(mContextSpy.getResources());
|
mResourcesSpy = spy(mContextSpy.getResources());
|
||||||
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
|
when(mContextSpy.getResources()).thenReturn(mResourcesSpy);
|
||||||
@@ -96,7 +92,7 @@ public final class AmbientSensorTest {
|
|||||||
// There should be no issues when we callback the listener, even if there is no callback
|
// There should be no issues when we callback the listener, even if there is no callback
|
||||||
// set.
|
// set.
|
||||||
SensorEventListener listener = captor.getValue();
|
SensorEventListener listener = captor.getValue();
|
||||||
listener.onSensorChanged(createSensorEvent(mLightSensor, 100));
|
listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -122,7 +118,7 @@ public final class AmbientSensorTest {
|
|||||||
verify(mSensorManagerMock).registerListener(captor.capture(), eq(mLightSensor),
|
verify(mSensorManagerMock).registerListener(captor.capture(), eq(mLightSensor),
|
||||||
anyInt(), eq(mHandler));
|
anyInt(), eq(mHandler));
|
||||||
SensorEventListener listener = captor.getValue();
|
SensorEventListener listener = captor.getValue();
|
||||||
listener.onSensorChanged(createSensorEvent(mLightSensor, luxValue));
|
listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, luxValue));
|
||||||
assertTrue(changeSignal.await(5, TimeUnit.SECONDS));
|
assertTrue(changeSignal.await(5, TimeUnit.SECONDS));
|
||||||
assertEquals(luxValue, luxReturned[0]);
|
assertEquals(luxValue, luxReturned[0]);
|
||||||
}
|
}
|
||||||
@@ -155,39 +151,8 @@ public final class AmbientSensorTest {
|
|||||||
verify(mSensorManagerMock).registerListener(captor.capture(), eq(mAmbientColorSensor),
|
verify(mSensorManagerMock).registerListener(captor.capture(), eq(mAmbientColorSensor),
|
||||||
anyInt(), eq(mHandler));
|
anyInt(), eq(mHandler));
|
||||||
SensorEventListener listener = captor.getValue();
|
SensorEventListener listener = captor.getValue();
|
||||||
listener.onSensorChanged(createSensorEvent(mAmbientColorSensor, colorTempValue));
|
listener.onSensorChanged(TestUtils.createSensorEvent(mAmbientColorSensor, colorTempValue));
|
||||||
assertTrue(changeSignal.await(5, TimeUnit.SECONDS));
|
assertTrue(changeSignal.await(5, TimeUnit.SECONDS));
|
||||||
assertEquals(colorTempValue, colorTempReturned[0]);
|
assertEquals(colorTempValue, colorTempReturned[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SensorEvent createSensorEvent(Sensor sensor, int lux) throws Exception {
|
|
||||||
final Constructor<SensorEvent> constructor =
|
|
||||||
SensorEvent.class.getDeclaredConstructor(int.class);
|
|
||||||
constructor.setAccessible(true);
|
|
||||||
final SensorEvent event = constructor.newInstance(1);
|
|
||||||
event.sensor = sensor;
|
|
||||||
event.values[0] = lux;
|
|
||||||
event.timestamp = SystemClock.elapsedRealtimeNanos();
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void setSensorType(Sensor sensor, int type, String strType) throws Exception {
|
|
||||||
Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
|
|
||||||
setter.setAccessible(true);
|
|
||||||
setter.invoke(sensor, type);
|
|
||||||
if (strType != null) {
|
|
||||||
Field f = sensor.getClass().getDeclaredField("mStringType");
|
|
||||||
f.setAccessible(true);
|
|
||||||
f.set(sensor, strType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Sensor createSensor(int type, String strType) throws Exception {
|
|
||||||
Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
|
|
||||||
constr.setAccessible(true);
|
|
||||||
Sensor sensor = constr.newInstance();
|
|
||||||
setSensorType(sensor, type, strType);
|
|
||||||
return sensor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user