Add support for custom keyboard backlight levels via IDC file
Test: atest KeyboardBacklightControllerTests Bug: 280797494 Change-Id: Ib9e919ad280d8f8f7adf3491fab2f69616af1762
This commit is contained in:
@@ -110,6 +110,8 @@ public final class Light implements Parcelable {
|
||||
private final int mOrdinal;
|
||||
private final int mType;
|
||||
private final int mCapabilities;
|
||||
@Nullable
|
||||
private final int[] mPreferredBrightnessLevels;
|
||||
|
||||
/**
|
||||
* Creates a new light with the given data.
|
||||
@@ -117,7 +119,7 @@ public final class Light implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public Light(int id, int ordinal, int type) {
|
||||
this(id, "Light", ordinal, type, 0);
|
||||
this(id, "Light", ordinal, type, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,11 +128,22 @@ public final class Light implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
public Light(int id, String name, int ordinal, int type, int capabilities) {
|
||||
this(id, name, ordinal, type, capabilities, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new light with the given data.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Light(int id, String name, int ordinal, int type, int capabilities,
|
||||
@Nullable int[] preferredBrightnessLevels) {
|
||||
mId = id;
|
||||
mName = name;
|
||||
mOrdinal = ordinal;
|
||||
mType = type;
|
||||
mCapabilities = capabilities;
|
||||
mPreferredBrightnessLevels = preferredBrightnessLevels;
|
||||
}
|
||||
|
||||
private Light(@NonNull Parcel in) {
|
||||
@@ -139,6 +152,7 @@ public final class Light implements Parcelable {
|
||||
mOrdinal = in.readInt();
|
||||
mType = in.readInt();
|
||||
mCapabilities = in.readInt();
|
||||
mPreferredBrightnessLevels = in.createIntArray();
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
@@ -149,6 +163,7 @@ public final class Light implements Parcelable {
|
||||
dest.writeInt(mOrdinal);
|
||||
dest.writeInt(mType);
|
||||
dest.writeInt(mCapabilities);
|
||||
dest.writeIntArray(mPreferredBrightnessLevels);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface */
|
||||
@@ -252,4 +267,17 @@ public final class Light implements Parcelable {
|
||||
return (mCapabilities & LIGHT_CAPABILITY_COLOR_RGB) == LIGHT_CAPABILITY_COLOR_RGB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns preferred brightness levels for the light which will be used when user
|
||||
* increase/decrease brightness levels for the light (currently only used for Keyboard
|
||||
* backlight control using backlight up/down keys).
|
||||
*
|
||||
* The values in the preferred brightness level array are in the range [0, 255].
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@Nullable
|
||||
public int[] getPreferredBrightnessLevels() {
|
||||
return mPreferredBrightnessLevels;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,15 @@ public final class InputFeatureFlagProvider {
|
||||
private static final boolean KEYBOARD_BACKLIGHT_ANIMATION_ENABLED =
|
||||
InputProperties.enable_keyboard_backlight_animation().orElse(false);
|
||||
|
||||
// To disable Custom keyboard backlight levels support via IDC files run:
|
||||
// adb shell setprop persist.input.keyboard_backlight_custom_levels.enabled false (requires
|
||||
// restart)
|
||||
private static final boolean KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED =
|
||||
InputProperties.enable_keyboard_backlight_custom_levels().orElse(true);
|
||||
|
||||
private static Optional<Boolean> sKeyboardBacklightControlOverride = Optional.empty();
|
||||
private static Optional<Boolean> sKeyboardBacklightAnimationOverride = Optional.empty();
|
||||
private static Optional<Boolean> sKeyboardBacklightCustomLevelsOverride = Optional.empty();
|
||||
|
||||
public static boolean isKeyboardBacklightControlEnabled() {
|
||||
return sKeyboardBacklightControlOverride.orElse(KEYBOARD_BACKLIGHT_CONTROL_ENABLED);
|
||||
@@ -49,6 +56,11 @@ public final class InputFeatureFlagProvider {
|
||||
return sKeyboardBacklightAnimationOverride.orElse(KEYBOARD_BACKLIGHT_ANIMATION_ENABLED);
|
||||
}
|
||||
|
||||
public static boolean isKeyboardBacklightCustomLevelsEnabled() {
|
||||
return sKeyboardBacklightCustomLevelsOverride.orElse(
|
||||
KEYBOARD_BACKLIGHT_CUSTOM_LEVELS_ENABLED);
|
||||
}
|
||||
|
||||
public static void setKeyboardBacklightControlEnabled(boolean enabled) {
|
||||
sKeyboardBacklightControlOverride = Optional.of(enabled);
|
||||
}
|
||||
@@ -57,11 +69,16 @@ public final class InputFeatureFlagProvider {
|
||||
sKeyboardBacklightAnimationOverride = Optional.of(enabled);
|
||||
}
|
||||
|
||||
public static void setKeyboardBacklightCustomLevelsEnabled(boolean enabled) {
|
||||
sKeyboardBacklightCustomLevelsOverride = Optional.of(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all input feature flag overrides.
|
||||
*/
|
||||
public static void clearOverrides() {
|
||||
sKeyboardBacklightControlOverride = Optional.empty();
|
||||
sKeyboardBacklightAnimationOverride = Optional.empty();
|
||||
sKeyboardBacklightCustomLevelsOverride = Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* A thread-safe component of {@link InputManagerService} responsible for managing the keyboard
|
||||
@@ -70,7 +71,9 @@ final class KeyboardBacklightController implements
|
||||
private static final int MSG_NOTIFY_USER_INACTIVITY = 5;
|
||||
private static final int MSG_INTERACTIVE_STATE_CHANGED = 6;
|
||||
private static final int MAX_BRIGHTNESS = 255;
|
||||
private static final int NUM_BRIGHTNESS_CHANGE_STEPS = 10;
|
||||
private static final int DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS = 10;
|
||||
@VisibleForTesting
|
||||
static final int MAX_BRIGHTNESS_CHANGE_STEPS = 10;
|
||||
private static final long TRANSITION_ANIMATION_DURATION_MILLIS =
|
||||
Duration.ofSeconds(1).toMillis();
|
||||
|
||||
@@ -80,7 +83,8 @@ final class KeyboardBacklightController implements
|
||||
static final long USER_INACTIVITY_THRESHOLD_MILLIS = Duration.ofSeconds(30).toMillis();
|
||||
|
||||
@VisibleForTesting
|
||||
static final int[] BRIGHTNESS_VALUE_FOR_LEVEL = new int[NUM_BRIGHTNESS_CHANGE_STEPS + 1];
|
||||
static final int[] DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL =
|
||||
new int[DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS + 1];
|
||||
|
||||
private final Context mContext;
|
||||
private final NativeInputManagerService mNative;
|
||||
@@ -104,10 +108,10 @@ final class KeyboardBacklightController implements
|
||||
static {
|
||||
// Fixed brightness levels to avoid issues when converting back and forth from the
|
||||
// device brightness range to [0-255]
|
||||
// Levels are: 0, 25, 51, ..., 255
|
||||
for (int i = 0; i <= NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
|
||||
BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor(
|
||||
((float) i * MAX_BRIGHTNESS) / NUM_BRIGHTNESS_CHANGE_STEPS);
|
||||
// Levels are: 0, 51, ..., 255
|
||||
for (int i = 0; i <= DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
|
||||
DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor(
|
||||
((float) i * MAX_BRIGHTNESS) / DEFAULT_NUM_BRIGHTNESS_CHANGE_STEPS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +188,8 @@ final class KeyboardBacklightController implements
|
||||
final int currBrightnessLevel = state.mBrightnessLevel;
|
||||
final int newBrightnessLevel;
|
||||
if (direction == Direction.DIRECTION_UP) {
|
||||
newBrightnessLevel = Math.min(currBrightnessLevel + 1, NUM_BRIGHTNESS_CHANGE_STEPS);
|
||||
newBrightnessLevel = Math.min(currBrightnessLevel + 1,
|
||||
state.getNumBrightnessChangeSteps());
|
||||
} else {
|
||||
newBrightnessLevel = Math.max(currBrightnessLevel - 1, 0);
|
||||
}
|
||||
@@ -194,7 +199,7 @@ final class KeyboardBacklightController implements
|
||||
try {
|
||||
mDataStore.setKeyboardBacklightBrightness(inputDevice.getDescriptor(),
|
||||
keyboardBacklight.getId(),
|
||||
BRIGHTNESS_VALUE_FOR_LEVEL[newBrightnessLevel]);
|
||||
state.mBrightnessValueForLevel[newBrightnessLevel]);
|
||||
} finally {
|
||||
mDataStore.saveIfNeeded();
|
||||
}
|
||||
@@ -202,6 +207,7 @@ final class KeyboardBacklightController implements
|
||||
}
|
||||
|
||||
private void restoreBacklightBrightness(InputDevice inputDevice, Light keyboardBacklight) {
|
||||
KeyboardBacklightState state = mKeyboardBacklights.get(inputDevice.getId());
|
||||
OptionalInt brightness;
|
||||
synchronized (mDataStore) {
|
||||
brightness = mDataStore.getKeyboardBacklightBrightness(
|
||||
@@ -209,9 +215,9 @@ final class KeyboardBacklightController implements
|
||||
}
|
||||
if (brightness.isPresent()) {
|
||||
int brightnessValue = Math.max(0, Math.min(MAX_BRIGHTNESS, brightness.getAsInt()));
|
||||
int index = Arrays.binarySearch(BRIGHTNESS_VALUE_FOR_LEVEL, brightnessValue);
|
||||
int index = Arrays.binarySearch(state.mBrightnessValueForLevel, brightnessValue);
|
||||
if (index < 0) {
|
||||
index = Math.min(NUM_BRIGHTNESS_CHANGE_STEPS, -(index + 1));
|
||||
index = Math.min(state.getNumBrightnessChangeSteps(), -(index + 1));
|
||||
}
|
||||
updateBacklightState(inputDevice.getId(), index, false /* isTriggeredByKeyPress */);
|
||||
if (DEBUG) {
|
||||
@@ -386,7 +392,7 @@ final class KeyboardBacklightController implements
|
||||
for (int i = 0; i < mKeyboardBacklightListenerRecords.size(); i++) {
|
||||
IKeyboardBacklightState callbackState = new IKeyboardBacklightState();
|
||||
callbackState.brightnessLevel = brightnessLevel;
|
||||
callbackState.maxBrightnessLevel = NUM_BRIGHTNESS_CHANGE_STEPS;
|
||||
callbackState.maxBrightnessLevel = state.getNumBrightnessChangeSteps();
|
||||
mKeyboardBacklightListenerRecords.valueAt(i).notifyKeyboardBacklightChanged(
|
||||
deviceId, callbackState, isTriggeredByKeyPress);
|
||||
}
|
||||
@@ -443,10 +449,6 @@ final class KeyboardBacklightController implements
|
||||
ipw.decreaseIndent();
|
||||
}
|
||||
|
||||
private static boolean isAnimationEnabled() {
|
||||
return InputFeatureFlagProvider.isKeyboardBacklightAnimationEnabled();
|
||||
}
|
||||
|
||||
// A record of a registered Keyboard backlight listener from one process.
|
||||
private class KeyboardBacklightListenerRecord implements IBinder.DeathRecipient {
|
||||
public final int mPid;
|
||||
@@ -482,18 +484,52 @@ final class KeyboardBacklightController implements
|
||||
private final Light mLight;
|
||||
private int mBrightnessLevel;
|
||||
private ValueAnimator mAnimator;
|
||||
private final int[] mBrightnessValueForLevel;
|
||||
|
||||
KeyboardBacklightState(int deviceId, Light light) {
|
||||
mDeviceId = deviceId;
|
||||
mLight = light;
|
||||
mBrightnessValueForLevel = setupBrightnessLevels();
|
||||
}
|
||||
|
||||
private int[] setupBrightnessLevels() {
|
||||
if (!InputFeatureFlagProvider.isKeyboardBacklightCustomLevelsEnabled()) {
|
||||
return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
|
||||
}
|
||||
int[] customLevels = mLight.getPreferredBrightnessLevels();
|
||||
if (customLevels == null || customLevels.length == 0) {
|
||||
return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
|
||||
}
|
||||
TreeSet<Integer> brightnessLevels = new TreeSet<>();
|
||||
brightnessLevels.add(0);
|
||||
for (int level : customLevels) {
|
||||
if (level > 0 && level < MAX_BRIGHTNESS) {
|
||||
brightnessLevels.add(level);
|
||||
}
|
||||
}
|
||||
brightnessLevels.add(MAX_BRIGHTNESS);
|
||||
int brightnessChangeSteps = brightnessLevels.size() - 1;
|
||||
if (brightnessChangeSteps > MAX_BRIGHTNESS_CHANGE_STEPS) {
|
||||
return DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL;
|
||||
}
|
||||
int[] result = new int[brightnessLevels.size()];
|
||||
int index = 0;
|
||||
for (int val : brightnessLevels) {
|
||||
result[index++] = val;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int getNumBrightnessChangeSteps() {
|
||||
return mBrightnessValueForLevel.length - 1;
|
||||
}
|
||||
|
||||
private void onBacklightStateChanged() {
|
||||
setBacklightValue(mIsBacklightOn ? BRIGHTNESS_VALUE_FOR_LEVEL[mBrightnessLevel] : 0);
|
||||
setBacklightValue(mIsBacklightOn ? mBrightnessValueForLevel[mBrightnessLevel] : 0);
|
||||
}
|
||||
private void setBrightnessLevel(int brightnessLevel) {
|
||||
if (mIsBacklightOn) {
|
||||
setBacklightValue(BRIGHTNESS_VALUE_FOR_LEVEL[brightnessLevel]);
|
||||
setBacklightValue(mBrightnessValueForLevel[brightnessLevel]);
|
||||
}
|
||||
mBrightnessLevel = brightnessLevel;
|
||||
}
|
||||
@@ -509,7 +545,7 @@ final class KeyboardBacklightController implements
|
||||
if (fromValue == toValue) {
|
||||
return;
|
||||
}
|
||||
if (isAnimationEnabled()) {
|
||||
if (InputFeatureFlagProvider.isKeyboardBacklightAnimationEnabled()) {
|
||||
startAnimation(fromValue, toValue);
|
||||
} else {
|
||||
mNative.setLightColor(mDeviceId, mLight.getId(), Color.argb(toValue, 0, 0, 0));
|
||||
|
||||
@@ -2214,13 +2214,25 @@ static jobject nativeGetLights(JNIEnv* env, jobject nativeImplObj, jint deviceId
|
||||
jCapability |= env->GetStaticIntField(gLightClassInfo.clazz,
|
||||
gLightClassInfo.lightCapabilityColorRgb);
|
||||
}
|
||||
|
||||
ScopedLocalRef<jintArray> jPreferredBrightnessLevels{env};
|
||||
if (!lightInfo.preferredBrightnessLevels.empty()) {
|
||||
std::vector<int32_t> vec;
|
||||
for (auto it : lightInfo.preferredBrightnessLevels) {
|
||||
vec.push_back(ftl::to_underlying(it));
|
||||
}
|
||||
jPreferredBrightnessLevels.reset(env->NewIntArray(vec.size()));
|
||||
env->SetIntArrayRegion(jPreferredBrightnessLevels.get(), 0, vec.size(), vec.data());
|
||||
}
|
||||
|
||||
ScopedLocalRef<jobject> lightObj(env,
|
||||
env->NewObject(gLightClassInfo.clazz,
|
||||
gLightClassInfo.constructor,
|
||||
static_cast<jint>(lightInfo.id),
|
||||
env->NewStringUTF(lightInfo.name.c_str()),
|
||||
static_cast<jint>(lightInfo.ordinal),
|
||||
jTypeId, jCapability));
|
||||
jTypeId, jCapability,
|
||||
jPreferredBrightnessLevels.get()));
|
||||
// Add light object to list
|
||||
env->CallBooleanMethod(jLights, gArrayListClassInfo.add, lightObj.get());
|
||||
}
|
||||
@@ -2846,7 +2858,7 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
FIND_CLASS(gLightClassInfo.clazz, "android/hardware/lights/Light");
|
||||
gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
|
||||
GET_METHOD_ID(gLightClassInfo.constructor, gLightClassInfo.clazz, "<init>",
|
||||
"(ILjava/lang/String;III)V");
|
||||
"(ILjava/lang/String;III[I)V");
|
||||
|
||||
gLightClassInfo.clazz = jclass(env->NewGlobalRef(gLightClassInfo.clazz));
|
||||
gLightClassInfo.lightTypeInput =
|
||||
|
||||
@@ -32,7 +32,8 @@ import android.platform.test.annotations.Presubmit
|
||||
import android.view.InputDevice
|
||||
import androidx.test.annotation.UiThreadTest
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.android.server.input.KeyboardBacklightController.BRIGHTNESS_VALUE_FOR_LEVEL
|
||||
import com.android.server.input.KeyboardBacklightController.DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL
|
||||
import com.android.server.input.KeyboardBacklightController.MAX_BRIGHTNESS_CHANGE_STEPS
|
||||
import com.android.server.input.KeyboardBacklightController.USER_INACTIVITY_THRESHOLD_MILLIS
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
@@ -65,12 +66,20 @@ private fun createKeyboard(deviceId: Int): InputDevice =
|
||||
.build()
|
||||
|
||||
private fun createLight(lightId: Int, lightType: Int): Light =
|
||||
createLight(
|
||||
lightId,
|
||||
lightType,
|
||||
null
|
||||
)
|
||||
|
||||
private fun createLight(lightId: Int, lightType: Int, suggestedBrightnessLevels: IntArray?): Light =
|
||||
Light(
|
||||
lightId,
|
||||
"Light $lightId",
|
||||
1,
|
||||
lightType,
|
||||
Light.LIGHT_CAPABILITY_BRIGHTNESS
|
||||
Light.LIGHT_CAPABILITY_BRIGHTNESS,
|
||||
suggestedBrightnessLevels
|
||||
)
|
||||
/**
|
||||
* Tests for {@link KeyboardBacklightController}.
|
||||
@@ -98,7 +107,6 @@ class KeyboardBacklightControllerTests {
|
||||
private lateinit var context: Context
|
||||
private lateinit var dataStore: PersistentDataStore
|
||||
private lateinit var testLooper: TestLooper
|
||||
private val totalLevels = BRIGHTNESS_VALUE_FOR_LEVEL.size
|
||||
private var lightColorMap: HashMap<Int, Int> = HashMap()
|
||||
private var lastBacklightState: KeyboardBacklightState? = null
|
||||
private var sysfsNodeChanges = 0
|
||||
@@ -146,84 +154,21 @@ class KeyboardBacklightControllerTests {
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklightIncrementDecrement() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
|
||||
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
|
||||
|
||||
for (level in 1 until totalLevels) {
|
||||
incrementKeyboardBacklight(DEVICE_ID)
|
||||
assertEquals(
|
||||
"Light value for level $level mismatched",
|
||||
Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
|
||||
lightColorMap[LIGHT_ID]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for level $level must be correctly stored in the datastore",
|
||||
BRIGHTNESS_VALUE_FOR_LEVEL[level],
|
||||
dataStore.getKeyboardBacklightBrightness(
|
||||
keyboardWithBacklight.descriptor,
|
||||
LIGHT_ID
|
||||
).asInt
|
||||
)
|
||||
}
|
||||
|
||||
// Increment above max level
|
||||
incrementKeyboardBacklight(DEVICE_ID)
|
||||
assertEquals(
|
||||
"Light value for max level mismatched",
|
||||
Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
|
||||
lightColorMap[LIGHT_ID]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for max level must be correctly stored in the datastore",
|
||||
MAX_BRIGHTNESS,
|
||||
dataStore.getKeyboardBacklightBrightness(
|
||||
keyboardWithBacklight.descriptor,
|
||||
LIGHT_ID
|
||||
).asInt
|
||||
)
|
||||
|
||||
for (level in totalLevels - 2 downTo 0) {
|
||||
decrementKeyboardBacklight(DEVICE_ID)
|
||||
assertEquals(
|
||||
"Light value for level $level mismatched",
|
||||
Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
|
||||
lightColorMap[LIGHT_ID]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for level $level must be correctly stored in the datastore",
|
||||
BRIGHTNESS_VALUE_FOR_LEVEL[level],
|
||||
dataStore.getKeyboardBacklightBrightness(
|
||||
keyboardWithBacklight.descriptor,
|
||||
LIGHT_ID
|
||||
).asInt
|
||||
)
|
||||
}
|
||||
|
||||
// Decrement below min level
|
||||
decrementKeyboardBacklight(DEVICE_ID)
|
||||
assertEquals(
|
||||
"Light value for min level mismatched",
|
||||
Color.argb(0, 0, 0, 0),
|
||||
lightColorMap[LIGHT_ID]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for min level must be correctly stored in the datastore",
|
||||
0,
|
||||
dataStore.getKeyboardBacklightBrightness(
|
||||
keyboardWithBacklight.descriptor,
|
||||
LIGHT_ID
|
||||
).asInt
|
||||
)
|
||||
assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
|
||||
DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKeyboardWithoutBacklight() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithoutBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardInputLight = createLight(LIGHT_ID, Light.LIGHT_TYPE_INPUT)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithoutBacklight)
|
||||
@@ -237,7 +182,7 @@ class KeyboardBacklightControllerTests {
|
||||
|
||||
@Test
|
||||
fun testKeyboardWithMultipleLight() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
val keyboardInputLight = createLight(SECOND_LIGHT_ID, Light.LIGHT_TYPE_INPUT)
|
||||
@@ -259,17 +204,17 @@ class KeyboardBacklightControllerTests {
|
||||
|
||||
@Test
|
||||
fun testRestoreBacklightOnInputDeviceAdded() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
|
||||
|
||||
for (level in 1 until totalLevels) {
|
||||
for (level in 1 until DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size) {
|
||||
dataStore.setKeyboardBacklightBrightness(
|
||||
keyboardWithBacklight.descriptor,
|
||||
LIGHT_ID,
|
||||
BRIGHTNESS_VALUE_FOR_LEVEL[level] - 1
|
||||
DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[level] - 1
|
||||
)
|
||||
|
||||
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
|
||||
@@ -278,7 +223,7 @@ class KeyboardBacklightControllerTests {
|
||||
assertEquals(
|
||||
"Keyboard backlight level should be restored to the level saved in the " +
|
||||
"data store",
|
||||
Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
|
||||
Color.argb(DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[level], 0, 0, 0),
|
||||
lightColorMap[LIGHT_ID]
|
||||
)
|
||||
keyboardBacklightController.onInputDeviceRemoved(DEVICE_ID)
|
||||
@@ -288,7 +233,7 @@ class KeyboardBacklightControllerTests {
|
||||
|
||||
@Test
|
||||
fun testRestoreBacklightOnInputDeviceChanged() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
@@ -320,9 +265,10 @@ class KeyboardBacklightControllerTests {
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklight_registerUnregisterListener() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
val maxLevel = DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size - 1
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
|
||||
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
|
||||
@@ -341,13 +287,13 @@ class KeyboardBacklightControllerTests {
|
||||
lastBacklightState!!.deviceId
|
||||
)
|
||||
assertEquals(
|
||||
"Backlight state brightnessLevel should be " + 1,
|
||||
"Backlight state brightnessLevel should be 1",
|
||||
1,
|
||||
lastBacklightState!!.brightnessLevel
|
||||
)
|
||||
assertEquals(
|
||||
"Backlight state maxBrightnessLevel should be " + (totalLevels - 1),
|
||||
(totalLevels - 1),
|
||||
"Backlight state maxBrightnessLevel should be $maxLevel",
|
||||
maxLevel,
|
||||
lastBacklightState!!.maxBrightnessLevel
|
||||
)
|
||||
assertEquals(
|
||||
@@ -368,7 +314,7 @@ class KeyboardBacklightControllerTests {
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklight_userActivity() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
@@ -400,7 +346,7 @@ class KeyboardBacklightControllerTests {
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklight_displayOnOff() {
|
||||
BacklightAnimationFlag(false).use {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
@@ -490,7 +436,7 @@ class KeyboardBacklightControllerTests {
|
||||
@Test
|
||||
@UiThreadTest
|
||||
fun testKeyboardBacklightAnimation_onChangeLevels() {
|
||||
BacklightAnimationFlag(true).use {
|
||||
KeyboardBacklightFlags(animationEnabled = true, customLevelsEnabled = false).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
@@ -500,17 +446,145 @@ class KeyboardBacklightControllerTests {
|
||||
incrementKeyboardBacklight(DEVICE_ID)
|
||||
assertEquals(
|
||||
"Should start animation from level 0",
|
||||
BRIGHTNESS_VALUE_FOR_LEVEL[0],
|
||||
DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[0],
|
||||
lastAnimationValues[0]
|
||||
)
|
||||
assertEquals(
|
||||
"Should start animation to level 1",
|
||||
BRIGHTNESS_VALUE_FOR_LEVEL[1],
|
||||
DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[1],
|
||||
lastAnimationValues[1]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklightPreferredLevels() {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val suggestedLevels = intArrayOf(0, 22, 63, 135, 196, 255)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
|
||||
suggestedLevels)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
|
||||
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
|
||||
|
||||
assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
|
||||
suggestedLevels)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklightPreferredLevels_moreThanMax_shouldUseDefault() {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val suggestedLevels = IntArray(MAX_BRIGHTNESS_CHANGE_STEPS + 1) { 10 * (it + 1) }
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
|
||||
suggestedLevels)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
|
||||
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
|
||||
|
||||
assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
|
||||
DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklightPreferredLevels_mustHaveZeroAndMaxBrightnessAsBounds() {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val suggestedLevels = intArrayOf(22, 63, 135, 196)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
|
||||
suggestedLevels)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
|
||||
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
|
||||
|
||||
// Framework will add the lowest and maximum levels if not provided via config
|
||||
assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
|
||||
intArrayOf(0, 22, 63, 135, 196, 255))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKeyboardBacklightPreferredLevels_dropsOutOfBoundsLevels() {
|
||||
KeyboardBacklightFlags(animationEnabled = false, customLevelsEnabled = true).use {
|
||||
val keyboardWithBacklight = createKeyboard(DEVICE_ID)
|
||||
val suggestedLevels = intArrayOf(22, 63, 135, 400, 196, 1000)
|
||||
val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT,
|
||||
suggestedLevels)
|
||||
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
|
||||
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
|
||||
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
|
||||
|
||||
// Framework will drop out of bound levels in the config
|
||||
assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight,
|
||||
intArrayOf(0, 22, 63, 135, 196, 255))
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertIncrementDecrementForLevels(
|
||||
device: InputDevice,
|
||||
light: Light,
|
||||
expectedLevels: IntArray
|
||||
) {
|
||||
val deviceId = device.id
|
||||
val lightId = light.id
|
||||
for (level in 1 until expectedLevels.size) {
|
||||
incrementKeyboardBacklight(deviceId)
|
||||
assertEquals(
|
||||
"Light value for level $level mismatched",
|
||||
Color.argb(expectedLevels[level], 0, 0, 0),
|
||||
lightColorMap[lightId]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for level $level must be correctly stored in the datastore",
|
||||
expectedLevels[level],
|
||||
dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
|
||||
)
|
||||
}
|
||||
|
||||
// Increment above max level
|
||||
incrementKeyboardBacklight(deviceId)
|
||||
assertEquals(
|
||||
"Light value for max level mismatched",
|
||||
Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
|
||||
lightColorMap[lightId]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for max level must be correctly stored in the datastore",
|
||||
MAX_BRIGHTNESS,
|
||||
dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
|
||||
)
|
||||
|
||||
for (level in expectedLevels.size - 2 downTo 0) {
|
||||
decrementKeyboardBacklight(deviceId)
|
||||
assertEquals(
|
||||
"Light value for level $level mismatched",
|
||||
Color.argb(expectedLevels[level], 0, 0, 0),
|
||||
lightColorMap[lightId]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for level $level must be correctly stored in the datastore",
|
||||
expectedLevels[level],
|
||||
dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
|
||||
)
|
||||
}
|
||||
|
||||
// Decrement below min level
|
||||
decrementKeyboardBacklight(deviceId)
|
||||
assertEquals(
|
||||
"Light value for min level mismatched",
|
||||
Color.argb(0, 0, 0, 0),
|
||||
lightColorMap[lightId]
|
||||
)
|
||||
assertEquals(
|
||||
"Light value for min level must be correctly stored in the datastore",
|
||||
0,
|
||||
dataStore.getKeyboardBacklightBrightness(device.descriptor, lightId).asInt
|
||||
)
|
||||
}
|
||||
|
||||
inner class KeyboardBacklightListener : IKeyboardBacklightListener.Stub() {
|
||||
override fun onBrightnessChanged(
|
||||
deviceId: Int,
|
||||
@@ -545,9 +619,13 @@ class KeyboardBacklightControllerTests {
|
||||
val isTriggeredByKeyPress: Boolean
|
||||
)
|
||||
|
||||
private inner class BacklightAnimationFlag constructor(enabled: Boolean) : AutoCloseable {
|
||||
private inner class KeyboardBacklightFlags constructor(
|
||||
animationEnabled: Boolean,
|
||||
customLevelsEnabled: Boolean
|
||||
) : AutoCloseable {
|
||||
init {
|
||||
InputFeatureFlagProvider.setKeyboardBacklightAnimationEnabled(enabled)
|
||||
InputFeatureFlagProvider.setKeyboardBacklightAnimationEnabled(animationEnabled)
|
||||
InputFeatureFlagProvider.setKeyboardBacklightCustomLevelsEnabled(customLevelsEnabled)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
|
||||
Reference in New Issue
Block a user