Merge "Add inactivity timer to turn off keyboard backlight"

This commit is contained in:
Vaibhav Devmurari
2023-01-13 14:33:14 +00:00
committed by Android (Google) Code Review
5 changed files with 279 additions and 124 deletions

View File

@@ -213,4 +213,10 @@ public abstract class InputManagerInternal {
* @param enabled When true, stylus buttons will not be reported through motion events.
*/
public abstract void setStylusButtonMotionEventsEnabled(boolean enabled);
/**
* Notify whether any user activity occurred. This includes any input activity on any
* display, external peripherals, fingerprint sensor, etc.
*/
public abstract void notifyUserActivity();
}

View File

@@ -3271,6 +3271,7 @@ public class InputManagerService extends IInputManager.Stub
public void setInteractive(boolean interactive) {
mNative.setInteractive(interactive);
mBatteryController.onInteractiveChanged(interactive);
mKeyboardBacklightController.onInteractiveChanged(interactive);
}
@Override
@@ -3357,6 +3358,11 @@ public class InputManagerService extends IInputManager.Stub
mKeyboardLayoutManager.onInputMethodSubtypeChanged(userId, subtypeHandle, subtype);
}
@Override
public void notifyUserActivity() {
mKeyboardBacklightController.notifyUserActivity();
}
@Override
public void incrementKeyboardBacklight(int deviceId) {
mKeyboardBacklightController.incrementKeyboardBacklight(deviceId);
@@ -3489,6 +3495,8 @@ public class InputManagerService extends IInputManager.Stub
default void decrementKeyboardBacklight(int deviceId) {}
default void registerKeyboardBacklightListener(IKeyboardBacklightListener l, int pid) {}
default void unregisterKeyboardBacklightListener(IKeyboardBacklightListener l, int pid) {}
default void onInteractiveChanged(boolean isInteractive) {}
default void notifyUserActivity() {}
default void systemRunning() {}
default void dump(PrintWriter pw) {}
}

View File

@@ -17,7 +17,6 @@
package com.android.server.input;
import android.annotation.BinderThread;
import android.annotation.ColorInt;
import android.content.Context;
import android.graphics.Color;
import android.hardware.input.IKeyboardBacklightListener;
@@ -29,6 +28,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
@@ -39,9 +39,10 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
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
@@ -59,12 +60,20 @@ final class KeyboardBacklightController implements
private enum Direction {
DIRECTION_UP, DIRECTION_DOWN
}
private static final int MSG_INCREMENT_KEYBOARD_BACKLIGHT = 1;
private static final int MSG_DECREMENT_KEYBOARD_BACKLIGHT = 2;
private static final int MSG_UPDATE_EXISTING_DEVICES = 1;
private static final int MSG_INCREMENT_KEYBOARD_BACKLIGHT = 2;
private static final int MSG_DECREMENT_KEYBOARD_BACKLIGHT = 3;
private static final int MSG_NOTIFY_USER_ACTIVITY = 4;
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;
@VisibleForTesting
static final TreeSet<Integer> BRIGHTNESS_LEVELS = new TreeSet<>();
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];
private final Context mContext;
private final NativeInputManagerService mNative;
@@ -72,7 +81,12 @@ final class KeyboardBacklightController implements
@GuardedBy("mDataStore")
private final PersistentDataStore mDataStore;
private final Handler mHandler;
private final SparseArray<Light> mKeyboardBacklights = new SparseArray<>();
// Always access on handler thread or need to lock this for synchronization.
private final SparseArray<KeyboardBacklightState> mKeyboardBacklights = new SparseArray<>(1);
// Maintains state if all backlights should be on or turned off
private boolean mIsBacklightOn = false;
// Maintains state if currently the device is interactive or not
private boolean mIsInteractive = true;
// List of currently registered keyboard backlight listeners
@GuardedBy("mKeyboardBacklightListenerRecords")
@@ -84,8 +98,8 @@ final class KeyboardBacklightController implements
// device brightness range to [0-255]
// Levels are: 0, 25, 51, ..., 255
for (int i = 0; i <= NUM_BRIGHTNESS_CHANGE_STEPS; i++) {
BRIGHTNESS_LEVELS.add(
(int) Math.floor(((float) i * MAX_BRIGHTNESS) / NUM_BRIGHTNESS_CHANGE_STEPS));
BRIGHTNESS_VALUE_FOR_LEVEL[i] = (int) Math.floor(
((float) i * MAX_BRIGHTNESS) / NUM_BRIGHTNESS_CHANGE_STEPS);
}
}
@@ -102,10 +116,10 @@ final class KeyboardBacklightController implements
InputManager inputManager = Objects.requireNonNull(
mContext.getSystemService(InputManager.class));
inputManager.registerInputDeviceListener(this, mHandler);
// Circle through all the already added input devices
for (int deviceId : inputManager.getInputDeviceIds()) {
onInputDeviceAdded(deviceId);
}
Message msg = Message.obtain(mHandler, MSG_UPDATE_EXISTING_DEVICES,
inputManager.getInputDeviceIds());
mHandler.sendMessage(msg);
}
@Override
@@ -120,37 +134,41 @@ final class KeyboardBacklightController implements
mHandler.sendMessage(msg);
}
@Override
public void notifyUserActivity() {
Message msg = Message.obtain(mHandler, MSG_NOTIFY_USER_ACTIVITY);
mHandler.sendMessage(msg);
}
@Override
public void onInteractiveChanged(boolean isInteractive) {
Message msg = Message.obtain(mHandler, MSG_INTERACTIVE_STATE_CHANGED, isInteractive);
mHandler.sendMessage(msg);
}
private void updateKeyboardBacklight(int deviceId, Direction direction) {
InputDevice inputDevice = getInputDevice(deviceId);
Light keyboardBacklight = mKeyboardBacklights.get(deviceId);
if (inputDevice == null || keyboardBacklight == null) {
KeyboardBacklightState state = mKeyboardBacklights.get(deviceId);
if (inputDevice == null || state == null) {
return;
}
Light keyboardBacklight = state.mLight;
// Follow preset levels of brightness defined in BRIGHTNESS_LEVELS
int currBrightness = BRIGHTNESS_LEVELS.floor(Color.alpha(
mNative.getLightColor(deviceId, keyboardBacklight.getId())));
int newBrightness;
final int currBrightnessLevel = state.mBrightnessLevel;
final int newBrightnessLevel;
if (direction == Direction.DIRECTION_UP) {
newBrightness = currBrightness != MAX_BRIGHTNESS ? BRIGHTNESS_LEVELS.higher(
currBrightness) : currBrightness;
newBrightnessLevel = Math.min(currBrightnessLevel + 1, NUM_BRIGHTNESS_CHANGE_STEPS);
} else {
newBrightness = currBrightness != 0 ? BRIGHTNESS_LEVELS.lower(currBrightness)
: currBrightness;
newBrightnessLevel = Math.max(currBrightnessLevel - 1, 0);
}
@ColorInt int newColor = Color.argb(newBrightness, 0, 0, 0);
mNative.setLightColor(deviceId, keyboardBacklight.getId(), newColor);
if (DEBUG) {
Slog.d(TAG, "Changing brightness from " + currBrightness + " to " + newBrightness);
}
notifyKeyboardBacklightChanged(deviceId, BRIGHTNESS_LEVELS.headSet(newBrightness).size(),
true/* isTriggeredByKeyPress */);
updateBacklightState(deviceId, keyboardBacklight, newBrightnessLevel,
true /* isTriggeredByKeyPress */);
synchronized (mDataStore) {
try {
mDataStore.setKeyboardBacklightBrightness(inputDevice.getDescriptor(),
keyboardBacklight.getId(),
newBrightness);
BRIGHTNESS_VALUE_FOR_LEVEL[newBrightnessLevel]);
} finally {
mDataStore.saveIfNeeded();
}
@@ -163,23 +181,83 @@ final class KeyboardBacklightController implements
brightness = mDataStore.getKeyboardBacklightBrightness(
inputDevice.getDescriptor(), keyboardBacklight.getId());
}
if (!brightness.isEmpty()) {
mNative.setLightColor(inputDevice.getId(), keyboardBacklight.getId(),
Color.argb(brightness.getAsInt(), 0, 0, 0));
if (brightness.isPresent()) {
int brightnessValue = Math.max(0, Math.min(MAX_BRIGHTNESS, brightness.getAsInt()));
int brightnessLevel = Arrays.binarySearch(BRIGHTNESS_VALUE_FOR_LEVEL, brightnessValue);
updateBacklightState(inputDevice.getId(), keyboardBacklight, brightnessLevel,
false /* isTriggeredByKeyPress */);
if (DEBUG) {
Slog.d(TAG, "Restoring brightness level " + brightness.getAsInt());
}
}
}
private void handleUserActivity() {
// Ignore user activity if device is not interactive. When device becomes interactive, we
// will send another user activity to turn backlight on.
if (!mIsInteractive) {
return;
}
if (!mIsBacklightOn) {
mIsBacklightOn = true;
for (int i = 0; i < mKeyboardBacklights.size(); i++) {
int deviceId = mKeyboardBacklights.keyAt(i);
KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
updateBacklightState(deviceId, state.mLight, state.mBrightnessLevel,
false /* isTriggeredByKeyPress */);
}
}
mHandler.removeMessages(MSG_NOTIFY_USER_INACTIVITY);
mHandler.sendEmptyMessageAtTime(MSG_NOTIFY_USER_INACTIVITY,
SystemClock.uptimeMillis() + USER_INACTIVITY_THRESHOLD_MILLIS);
}
private void handleUserInactivity() {
if (mIsBacklightOn) {
mIsBacklightOn = false;
for (int i = 0; i < mKeyboardBacklights.size(); i++) {
int deviceId = mKeyboardBacklights.keyAt(i);
KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
updateBacklightState(deviceId, state.mLight, state.mBrightnessLevel,
false /* isTriggeredByKeyPress */);
}
}
}
@VisibleForTesting
public void handleInteractiveStateChange(boolean isInteractive) {
// Interactive state changes should force the keyboard to turn on/off irrespective of
// whether time out occurred or not.
mIsInteractive = isInteractive;
if (isInteractive) {
handleUserActivity();
} else {
handleUserInactivity();
}
}
private boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_EXISTING_DEVICES:
for (int deviceId : (int[]) msg.obj) {
onInputDeviceAdded(deviceId);
}
return true;
case MSG_INCREMENT_KEYBOARD_BACKLIGHT:
updateKeyboardBacklight((int) msg.obj, Direction.DIRECTION_UP);
return true;
case MSG_DECREMENT_KEYBOARD_BACKLIGHT:
updateKeyboardBacklight((int) msg.obj, Direction.DIRECTION_DOWN);
return true;
case MSG_NOTIFY_USER_ACTIVITY:
handleUserActivity();
return true;
case MSG_NOTIFY_USER_INACTIVITY:
handleUserInactivity();
return true;
case MSG_INTERACTIVE_STATE_CHANGED:
handleInteractiveStateChange((boolean) msg.obj);
return true;
}
return false;
}
@@ -208,12 +286,12 @@ final class KeyboardBacklightController implements
mKeyboardBacklights.remove(deviceId);
return;
}
final Light oldBacklight = mKeyboardBacklights.get(deviceId);
if (oldBacklight != null && oldBacklight.getId() == keyboardBacklight.getId()) {
KeyboardBacklightState state = mKeyboardBacklights.get(deviceId);
if (state != null && state.mLight.getId() == keyboardBacklight.getId()) {
return;
}
// The keyboard backlight was added or changed.
mKeyboardBacklights.put(deviceId, keyboardBacklight);
mKeyboardBacklights.put(deviceId, new KeyboardBacklightState(keyboardBacklight));
restoreBacklightBrightness(inputDevice, keyboardBacklight);
}
@@ -275,13 +353,29 @@ final class KeyboardBacklightController implements
}
}
private void notifyKeyboardBacklightChanged(int deviceId, int currentBacklightLevel,
private void updateBacklightState(int deviceId, Light light, int brightnessLevel,
boolean isTriggeredByKeyPress) {
KeyboardBacklightState state = mKeyboardBacklights.get(deviceId);
if (state == null) {
return;
}
mNative.setLightColor(deviceId, light.getId(),
mIsBacklightOn ? Color.argb(BRIGHTNESS_VALUE_FOR_LEVEL[brightnessLevel], 0, 0, 0)
: 0);
if (DEBUG) {
Slog.d(TAG, "Changing state from " + state.mBrightnessLevel + " to " + brightnessLevel
+ "(isBacklightOn = " + mIsBacklightOn + ")");
}
state.mBrightnessLevel = brightnessLevel;
synchronized (mKeyboardBacklightListenerRecords) {
for (int i = 0; i < mKeyboardBacklightListenerRecords.size(); i++) {
IKeyboardBacklightState callbackState = new IKeyboardBacklightState();
callbackState.brightnessLevel = brightnessLevel;
callbackState.maxBrightnessLevel = NUM_BRIGHTNESS_CHANGE_STEPS;
mKeyboardBacklightListenerRecords.valueAt(i).notifyKeyboardBacklightChanged(
deviceId, new KeyboardBacklightState(currentBacklightLevel),
isTriggeredByKeyPress);
deviceId, callbackState, isTriggeredByKeyPress);
}
}
}
@@ -295,11 +389,14 @@ final class KeyboardBacklightController implements
@Override
public void dump(PrintWriter pw) {
IndentingPrintWriter ipw = new IndentingPrintWriter(pw);
ipw.println(TAG + ": " + mKeyboardBacklights.size() + " keyboard backlights");
ipw.println(
TAG + ": " + mKeyboardBacklights.size() + " keyboard backlights, isBacklightOn = "
+ mIsBacklightOn);
ipw.increaseIndent();
for (int i = 0; i < mKeyboardBacklights.size(); i++) {
Light light = mKeyboardBacklights.get(i);
ipw.println(i + ": { id: " + light.getId() + ", name: " + light.getName() + " }");
KeyboardBacklightState state = mKeyboardBacklights.valueAt(i);
ipw.println(i + ": " + state.toString());
}
ipw.decreaseIndent();
}
@@ -334,17 +431,18 @@ final class KeyboardBacklightController implements
}
}
private static class KeyboardBacklightState extends IKeyboardBacklightState {
private static class KeyboardBacklightState {
private final Light mLight;
private int mBrightnessLevel;
KeyboardBacklightState(int brightnessLevel) {
this.brightnessLevel = brightnessLevel;
this.maxBrightnessLevel = NUM_BRIGHTNESS_CHANGE_STEPS;
KeyboardBacklightState(Light light) {
mLight = light;
}
@Override
public String toString() {
return "KeyboardBacklightState{brightnessLevel=" + brightnessLevel
+ ", maxBrightnessLevel=" + maxBrightnessLevel
return "KeyboardBacklightState{Light=" + mLight.getId()
+ ", BrightnessLevel=" + mBrightnessLevel
+ "}";
}
}

View File

@@ -737,6 +737,7 @@ public class Notifier {
}
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
tm.notifyUserActivity();
mInputManagerInternal.notifyUserActivity();
mPolicy.userActivity(displayGroupId, event);
mFaceDownDetector.userActivity(event);
mScreenUndimDetector.userActivity(displayGroupId);

View File

@@ -28,7 +28,8 @@ import android.os.test.TestLooper
import android.platform.test.annotations.Presubmit
import android.view.InputDevice
import androidx.test.core.app.ApplicationProvider
import com.android.server.input.KeyboardBacklightController.BRIGHTNESS_LEVELS
import com.android.server.input.KeyboardBacklightController.BRIGHTNESS_VALUE_FOR_LEVEL
import com.android.server.input.KeyboardBacklightController.USER_INACTIVITY_THRESHOLD_MILLIS
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
@@ -78,6 +79,7 @@ class KeyboardBacklightControllerTests {
const val DEVICE_ID = 1
const val LIGHT_ID = 2
const val SECOND_LIGHT_ID = 3
const val MAX_BRIGHTNESS = 255
}
@get:Rule
@@ -118,10 +120,6 @@ class KeyboardBacklightControllerTests {
val args = it.arguments
lightColorMap.put(args[1] as Int, args[2] as Int)
}
`when`(native.getLightColor(anyInt(), anyInt())).then {
val args = it.arguments
lightColorMap.getOrDefault(args[1] as Int, -1)
}
lightColorMap.clear()
}
@@ -137,21 +135,17 @@ class KeyboardBacklightControllerTests {
`when`(iInputManager.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
// Initially backlight is at min
lightColorMap[LIGHT_ID] = Color.argb(BRIGHTNESS_LEVELS.first(), 0, 0, 0)
val brightnessLevelsArray = BRIGHTNESS_LEVELS.toTypedArray()
for (level in 1 until brightnessLevelsArray.size) {
keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
testLooper.dispatchNext()
for (level in 1 until BRIGHTNESS_VALUE_FOR_LEVEL.size) {
incrementKeyboardBacklight(DEVICE_ID)
assertEquals(
"Light value for level $level mismatched",
Color.argb(brightnessLevelsArray[level], 0, 0, 0),
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",
brightnessLevelsArray[level],
BRIGHTNESS_VALUE_FOR_LEVEL[level],
dataStore.getKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID
@@ -159,72 +153,49 @@ class KeyboardBacklightControllerTests {
)
}
for (level in brightnessLevelsArray.size - 2 downTo 0) {
keyboardBacklightController.decrementKeyboardBacklight(DEVICE_ID)
testLooper.dispatchNext()
assertEquals(
"Light value for level $level mismatched",
Color.argb(brightnessLevelsArray[level], 0, 0, 0),
lightColorMap[LIGHT_ID]
)
assertEquals(
"Light value for level $level must be correctly stored in the datastore",
brightnessLevelsArray[level],
dataStore.getKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID
).asInt
)
}
}
@Test
fun testKeyboardBacklightIncrementAboveMaxLevel() {
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)
// Initially backlight is at max
lightColorMap[LIGHT_ID] = Color.argb(BRIGHTNESS_LEVELS.last(), 0, 0, 0)
keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
testLooper.dispatchNext()
// Increment above max level
incrementKeyboardBacklight(DEVICE_ID)
assertEquals(
"Light value for max level mismatched",
Color.argb(BRIGHTNESS_LEVELS.last(), 0, 0, 0),
Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
lightColorMap[LIGHT_ID]
)
assertEquals(
"Light value for max level must be correctly stored in the datastore",
BRIGHTNESS_LEVELS.last(),
MAX_BRIGHTNESS,
dataStore.getKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID
).asInt
)
}
@Test
fun testKeyboardBacklightDecrementBelowMin() {
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)
// Initially backlight is at min
lightColorMap[LIGHT_ID] = Color.argb(BRIGHTNESS_LEVELS.first(), 0, 0, 0)
for (level in BRIGHTNESS_VALUE_FOR_LEVEL.size - 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
)
}
keyboardBacklightController.decrementKeyboardBacklight(DEVICE_ID)
testLooper.dispatchNext()
// Decrement below min level
decrementKeyboardBacklight(DEVICE_ID)
assertEquals(
"Light value for min level mismatched",
Color.argb(BRIGHTNESS_LEVELS.first(), 0, 0, 0),
Color.argb(0, 0, 0, 0),
lightColorMap[LIGHT_ID]
)
assertEquals(
"Light value for min level must be correctly stored in the datastore",
BRIGHTNESS_LEVELS.first(),
0,
dataStore.getKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID
@@ -240,7 +211,7 @@ class KeyboardBacklightControllerTests {
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardInputLight))
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
incrementKeyboardBacklight(DEVICE_ID)
assertTrue("Non Keyboard backlights should not change", lightColorMap.isEmpty())
}
@@ -258,8 +229,7 @@ class KeyboardBacklightControllerTests {
)
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
testLooper.dispatchNext()
incrementKeyboardBacklight(DEVICE_ID)
assertEquals("Only keyboard backlights should change", 1, lightColorMap.size)
assertNotNull("Keyboard backlight should change", lightColorMap[LIGHT_ID])
assertNull("Input lights should not change", lightColorMap[SECOND_LIGHT_ID])
@@ -275,14 +245,15 @@ class KeyboardBacklightControllerTests {
dataStore.setKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID,
BRIGHTNESS_LEVELS.last()
MAX_BRIGHTNESS
)
lightColorMap.clear()
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
keyboardBacklightController.notifyUserActivity()
testLooper.dispatchNext()
assertEquals(
"Keyboard backlight level should be restored to the level saved in the data store",
Color.argb(BRIGHTNESS_LEVELS.last(), 0, 0, 0),
Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
lightColorMap[LIGHT_ID]
)
}
@@ -295,11 +266,12 @@ class KeyboardBacklightControllerTests {
dataStore.setKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID,
BRIGHTNESS_LEVELS.last()
MAX_BRIGHTNESS
)
lightColorMap.clear()
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
keyboardBacklightController.notifyUserActivity()
testLooper.dispatchNext()
assertTrue(
"Keyboard backlight should not be changed until its added",
lightColorMap.isEmpty()
@@ -307,22 +279,22 @@ class KeyboardBacklightControllerTests {
`when`(iInputManager.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
keyboardBacklightController.onInputDeviceChanged(DEVICE_ID)
keyboardBacklightController.notifyUserActivity()
testLooper.dispatchNext()
assertEquals(
"Keyboard backlight level should be restored to the level saved in the data store",
Color.argb(BRIGHTNESS_LEVELS.last(), 0, 0, 0),
Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
lightColorMap[LIGHT_ID]
)
}
@Test
fun testKeyboardBacklightT_registerUnregisterListener() {
fun testKeyboardBacklight_registerUnregisterListener() {
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)
// Initially backlight is at min
lightColorMap[LIGHT_ID] = Color.argb(BRIGHTNESS_LEVELS.first(), 0, 0, 0)
// Register backlight listener
val listener = KeyboardBacklightListener()
@@ -343,8 +315,8 @@ class KeyboardBacklightControllerTests {
lastBacklightState!!.brightnessLevel
)
assertEquals(
"Backlight state maxBrightnessLevel should be " + (BRIGHTNESS_LEVELS.size - 1),
(BRIGHTNESS_LEVELS.size - 1),
"Backlight state maxBrightnessLevel should be " + (BRIGHTNESS_VALUE_FOR_LEVEL.size - 1),
(BRIGHTNESS_VALUE_FOR_LEVEL.size - 1),
lastBacklightState!!.maxBrightnessLevel
)
assertEquals(
@@ -357,12 +329,70 @@ class KeyboardBacklightControllerTests {
keyboardBacklightController.unregisterKeyboardBacklightListener(listener, 0)
lastBacklightState = null
keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
testLooper.dispatchNext()
incrementKeyboardBacklight(DEVICE_ID)
assertNull("Listener should not receive any updates", lastBacklightState)
}
@Test
fun testKeyboardBacklight_userActivity() {
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))
dataStore.setKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID,
MAX_BRIGHTNESS
)
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
keyboardBacklightController.notifyUserActivity()
testLooper.dispatchNext()
assertEquals(
"Keyboard backlight level should be restored to the level saved in the data store",
Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
lightColorMap[LIGHT_ID]
)
testLooper.moveTimeForward(USER_INACTIVITY_THRESHOLD_MILLIS + 1000)
testLooper.dispatchNext()
assertEquals(
"Keyboard backlight level should be turned off after inactivity",
0,
lightColorMap[LIGHT_ID]
)
}
@Test
fun testKeyboardBacklight_displayOnOff() {
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))
dataStore.setKeyboardBacklightBrightness(
keyboardWithBacklight.descriptor,
LIGHT_ID,
MAX_BRIGHTNESS
)
keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
keyboardBacklightController.handleInteractiveStateChange(true /* isDisplayOn */)
assertEquals(
"Keyboard backlight level should be restored to the level saved in the data " +
"store when display turned on",
Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
lightColorMap[LIGHT_ID]
)
keyboardBacklightController.handleInteractiveStateChange(false /* isDisplayOn */)
assertEquals(
"Keyboard backlight level should be turned off after display is turned off",
0,
lightColorMap[LIGHT_ID]
)
}
inner class KeyboardBacklightListener : IKeyboardBacklightListener.Stub() {
override fun onBrightnessChanged(
deviceId: Int,
@@ -378,6 +408,18 @@ class KeyboardBacklightControllerTests {
}
}
private fun incrementKeyboardBacklight(deviceId: Int) {
keyboardBacklightController.incrementKeyboardBacklight(deviceId)
keyboardBacklightController.notifyUserActivity()
testLooper.dispatchAll()
}
private fun decrementKeyboardBacklight(deviceId: Int) {
keyboardBacklightController.decrementKeyboardBacklight(deviceId)
keyboardBacklightController.notifyUserActivity()
testLooper.dispatchAll()
}
class KeyboardBacklightState(
val deviceId: Int,
val brightnessLevel: Int,