1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.android.server.input
18
19 import android.animation.ValueAnimator
20 import android.content.Context
21 import android.content.ContextWrapper
22 import android.content.res.Resources
23 import android.graphics.Color
24 import android.hardware.input.IKeyboardBacklightListener
25 import android.hardware.input.IKeyboardBacklightState
26 import android.hardware.input.InputManager
27 import android.hardware.lights.Light
28 import android.os.SystemProperties
29 import android.os.test.TestLooper
30 import android.platform.test.annotations.Presubmit
31 import android.util.TypedValue
32 import android.view.InputDevice
33 import androidx.test.annotation.UiThreadTest
34 import androidx.test.core.app.ApplicationProvider
35 import com.android.dx.mockito.inline.extended.ExtendedMockito
36 import com.android.internal.R
37 import com.android.modules.utils.testing.ExtendedMockitoRule
38 import com.android.server.input.KeyboardBacklightController.DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL
39 import com.android.server.input.KeyboardBacklightController.MAX_BRIGHTNESS_CHANGE_STEPS
40 import com.android.test.input.MockInputManagerRule
41 import org.junit.Assert.assertEquals
42 import org.junit.Assert.assertNotEquals
43 import org.junit.Assert.assertNotNull
44 import org.junit.Assert.assertNull
45 import org.junit.Assert.assertTrue
46 import org.junit.Before
47 import org.junit.Rule
48 import org.junit.Test
49 import org.mockito.Mock
50 import org.mockito.Mockito.any
51 import org.mockito.Mockito.anyBoolean
52 import org.mockito.Mockito.anyInt
53 import org.mockito.Mockito.eq
54 import org.mockito.Mockito.spy
55 import org.mockito.Mockito.`when`
56
createKeyboardnull57 private fun createKeyboard(deviceId: Int): InputDevice =
58 InputDevice.Builder()
59 .setId(deviceId)
60 .setName("Device $deviceId")
61 .setDescriptor("descriptor $deviceId")
62 .setSources(InputDevice.SOURCE_KEYBOARD)
63 .setKeyboardType(InputDevice.KEYBOARD_TYPE_ALPHABETIC)
64 .setExternal(true)
65 .build()
66
67 private fun createLight(lightId: Int, lightType: Int): Light = createLight(lightId, lightType, null)
68
69 private fun createLight(lightId: Int, lightType: Int, suggestedBrightnessLevels: IntArray?): Light =
70 Light(
71 lightId,
72 "Light $lightId",
73 1,
74 lightType,
75 Light.LIGHT_CAPABILITY_BRIGHTNESS,
76 suggestedBrightnessLevels,
77 )
78
79 /**
80 * Tests for {@link KeyboardBacklightController}.
81 *
82 * Build/Install/Run: atest InputTests:KeyboardBacklightControllerTests
83 */
84 @Presubmit
85 class KeyboardBacklightControllerTests {
86 companion object {
87 const val DEVICE_ID = 1
88 const val LIGHT_ID = 2
89 const val SECOND_LIGHT_ID = 3
90 const val MAX_BRIGHTNESS = 255
91 const val USER_INACTIVITY_THRESHOLD_MILLIS = 30000
92 }
93
94 @get:Rule
95 val extendedMockitoRule =
96 ExtendedMockitoRule.Builder(this).mockStatic(SystemProperties::class.java).build()!!
97 @get:Rule val inputManagerRule = MockInputManagerRule()
98
99 @Mock private lateinit var native: NativeInputManagerService
100 @Mock private lateinit var resources: Resources
101 private lateinit var keyboardBacklightController: KeyboardBacklightController
102 private lateinit var context: Context
103 private lateinit var testLooper: TestLooper
104 private var lightColorMap: HashMap<Int, Int> = HashMap()
105 private var lastBacklightState: KeyboardBacklightState? = null
106 private var lastAnimationValues = IntArray(2)
107
108 @Before
109 fun setup() {
110 context = spy(ContextWrapper(ApplicationProvider.getApplicationContext()))
111 `when`(context.resources).thenReturn(resources)
112 testLooper = TestLooper()
113 setupConfig()
114 val inputManager = InputManager(context)
115 `when`(context.getSystemService(eq(Context.INPUT_SERVICE))).thenReturn(inputManager)
116 `when`(inputManagerRule.mock.inputDeviceIds).thenReturn(intArrayOf(DEVICE_ID))
117 `when`(native.setLightColor(anyInt(), anyInt(), anyInt())).then {
118 val args = it.arguments
119 lightColorMap.put(args[1] as Int, args[2] as Int)
120 }
121 `when`(native.getLightColor(anyInt(), anyInt())).thenAnswer {
122 val args = it.arguments
123 lightColorMap.getOrDefault(args[1] as Int, 0)
124 }
125 lightColorMap.clear()
126 }
127
128 private fun setupConfig() {
129 val brightnessValues = intArrayOf(100, 200, 0)
130 val decreaseThresholds = intArrayOf(-1, 900, 1900)
131 val increaseThresholds = intArrayOf(1000, 2000, -1)
132 `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightBrightnessValues))
133 .thenReturn(brightnessValues)
134 `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightDecreaseLuxThreshold))
135 .thenReturn(decreaseThresholds)
136 `when`(resources.getIntArray(R.array.config_autoKeyboardBacklightIncreaseLuxThreshold))
137 .thenReturn(increaseThresholds)
138 `when`(resources.getInteger(R.integer.config_keyboardBacklightTimeoutMs))
139 .thenReturn(USER_INACTIVITY_THRESHOLD_MILLIS)
140 `when`(
141 resources.getValue(
142 eq(R.dimen.config_autoKeyboardBrightnessSmoothingConstant),
143 any(TypedValue::class.java),
144 anyBoolean(),
145 )
146 )
147 .then {
148 val args = it.arguments
149 val outValue = args[1] as TypedValue
150 outValue.data = java.lang.Float.floatToRawIntBits(1.0f)
151 Unit
152 }
153 }
154
155 private fun setupController() {
156 keyboardBacklightController =
157 KeyboardBacklightController(context, native, testLooper.looper, FakeAnimatorFactory())
158 }
159
160 @Test
161 fun testKeyboardBacklightIncrementDecrement() {
162 setupController()
163 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
164 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
165 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
166 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
167 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
168
169 assertIncrementDecrementForLevels(
170 keyboardWithBacklight,
171 keyboardBacklight,
172 DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL,
173 )
174 }
175
176 @Test
177 fun testKeyboardWithoutBacklight() {
178 setupController()
179 val keyboardWithoutBacklight = createKeyboard(DEVICE_ID)
180 val keyboardInputLight = createLight(LIGHT_ID, Light.LIGHT_TYPE_INPUT)
181 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithoutBacklight)
182 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardInputLight))
183 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
184
185 incrementKeyboardBacklight(DEVICE_ID)
186 assertTrue("Non Keyboard backlights should not change", lightColorMap.isEmpty())
187 }
188
189 @Test
190 fun testKeyboardWithMultipleLight() {
191 setupController()
192 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
193 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
194 val keyboardInputLight = createLight(SECOND_LIGHT_ID, Light.LIGHT_TYPE_INPUT)
195 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
196 `when`(inputManagerRule.mock.getLights(DEVICE_ID))
197 .thenReturn(listOf(keyboardBacklight, keyboardInputLight))
198 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
199
200 incrementKeyboardBacklight(DEVICE_ID)
201 assertEquals("Only keyboard backlights should change", 1, lightColorMap.size)
202 assertNotNull("Keyboard backlight should change", lightColorMap[LIGHT_ID])
203 assertNull("Input lights should not change", lightColorMap[SECOND_LIGHT_ID])
204 }
205
206 @Test
207 fun testKeyboardBacklight_registerUnregisterListener() {
208 setupController()
209 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
210 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
211 val maxLevel = DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size - 1
212 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
213 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
214 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
215
216 // Register backlight listener
217 val listener = KeyboardBacklightListener()
218 keyboardBacklightController.registerKeyboardBacklightListener(listener, 0)
219
220 lastBacklightState = null
221 keyboardBacklightController.incrementKeyboardBacklight(DEVICE_ID)
222 testLooper.dispatchNext()
223
224 assertEquals(
225 "Backlight state device Id should be $DEVICE_ID",
226 DEVICE_ID,
227 lastBacklightState!!.deviceId,
228 )
229 assertEquals(
230 "Backlight state brightnessLevel should be 1",
231 1,
232 lastBacklightState!!.brightnessLevel,
233 )
234 assertEquals(
235 "Backlight state maxBrightnessLevel should be $maxLevel",
236 maxLevel,
237 lastBacklightState!!.maxBrightnessLevel,
238 )
239 assertEquals(
240 "Backlight state isTriggeredByKeyPress should be true",
241 true,
242 lastBacklightState!!.isTriggeredByKeyPress,
243 )
244
245 // Unregister listener
246 keyboardBacklightController.unregisterKeyboardBacklightListener(listener, 0)
247
248 lastBacklightState = null
249 incrementKeyboardBacklight(DEVICE_ID)
250
251 assertNull("Listener should not receive any updates", lastBacklightState)
252 }
253
254 @Test
255 fun testKeyboardBacklight_userActivity() {
256 setupController()
257 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
258 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
259 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
260 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
261 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
262 incrementKeyboardBacklight(DEVICE_ID)
263 assertNotEquals(
264 "Keyboard backlight level should be incremented to a non-zero value",
265 0,
266 lightColorMap[LIGHT_ID],
267 )
268
269 testLooper.moveTimeForward((USER_INACTIVITY_THRESHOLD_MILLIS + 1000).toLong())
270 testLooper.dispatchNext()
271 assertEquals(
272 "Keyboard backlight level should be turned off after inactivity",
273 0,
274 lightColorMap[LIGHT_ID],
275 )
276 }
277
278 @Test
279 fun testKeyboardBacklight_displayOnOff() {
280 setupController()
281 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
282 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
283 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
284 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
285 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
286 incrementKeyboardBacklight(DEVICE_ID)
287
288 val currentValue = lightColorMap[LIGHT_ID]
289 assertNotEquals(
290 "Keyboard backlight level should be incremented to a non-zero value",
291 0,
292 lightColorMap[LIGHT_ID],
293 )
294
295 keyboardBacklightController.handleInteractiveStateChange(false /* isDisplayOn */)
296 assertEquals(
297 "Keyboard backlight level should be turned off after display is turned off",
298 0,
299 lightColorMap[LIGHT_ID],
300 )
301
302 keyboardBacklightController.handleInteractiveStateChange(true /* isDisplayOn */)
303 assertEquals(
304 "Keyboard backlight level should be turned on after display is turned on",
305 currentValue,
306 lightColorMap[LIGHT_ID],
307 )
308 }
309
310 @Test
311 @UiThreadTest
312 fun testKeyboardBacklightAnimation_onChangeLevels() {
313 ExtendedMockito.doReturn("true").`when` {
314 SystemProperties.get(eq("persist.input.keyboard.backlight_animation.enabled"))
315 }
316 setupController()
317 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
318 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
319 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
320 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
321 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
322
323 incrementKeyboardBacklight(DEVICE_ID)
324 assertEquals(
325 "Should start animation from level 0",
326 DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[0],
327 lastAnimationValues[0],
328 )
329 assertEquals(
330 "Should start animation to level 1",
331 DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[1],
332 lastAnimationValues[1],
333 )
334 }
335
336 @Test
337 fun testKeyboardBacklightPreferredLevels() {
338 setupController()
339 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
340 val suggestedLevels = intArrayOf(0, 22, 63, 135, 196, 255)
341 val keyboardBacklight =
342 createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, suggestedLevels)
343 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
344 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
345 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
346
347 assertIncrementDecrementForLevels(keyboardWithBacklight, keyboardBacklight, suggestedLevels)
348 }
349
350 @Test
351 fun testKeyboardBacklightPreferredLevels_moreThanMax_shouldUseDefault() {
352 setupController()
353 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
354 val suggestedLevels = IntArray(MAX_BRIGHTNESS_CHANGE_STEPS + 1) { 10 * (it + 1) }
355 val keyboardBacklight =
356 createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, suggestedLevels)
357 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
358 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
359 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
360
361 assertIncrementDecrementForLevels(
362 keyboardWithBacklight,
363 keyboardBacklight,
364 DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL,
365 )
366 }
367
368 @Test
369 fun testKeyboardBacklightPreferredLevels_mustHaveZeroAndMaxBrightnessAsBounds() {
370 setupController()
371 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
372 val suggestedLevels = intArrayOf(22, 63, 135, 196)
373 val keyboardBacklight =
374 createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, suggestedLevels)
375 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
376 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
377 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
378
379 // Framework will add the lowest and maximum levels if not provided via config
380 assertIncrementDecrementForLevels(
381 keyboardWithBacklight,
382 keyboardBacklight,
383 intArrayOf(0, 22, 63, 135, 196, 255),
384 )
385 }
386
387 @Test
388 fun testKeyboardBacklightPreferredLevels_dropsOutOfBoundsLevels() {
389 setupController()
390 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
391 val suggestedLevels = intArrayOf(22, 63, 135, 400, 196, 1000)
392 val keyboardBacklight =
393 createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT, suggestedLevels)
394 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
395 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
396 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
397
398 // Framework will drop out of bound levels in the config
399 assertIncrementDecrementForLevels(
400 keyboardWithBacklight,
401 keyboardBacklight,
402 intArrayOf(0, 22, 63, 135, 196, 255),
403 )
404 }
405
406 @Test
407 fun testAmbientBacklightControl_incrementLevel_afterAmbientChange() {
408 setupController()
409 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
410 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
411 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
412 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
413 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
414 sendAmbientBacklightValue(1)
415 assertEquals(
416 "Light value should be changed to ambient provided value",
417 Color.argb(1, 0, 0, 0),
418 lightColorMap[LIGHT_ID],
419 )
420
421 incrementKeyboardBacklight(DEVICE_ID)
422
423 assertEquals(
424 "Light value for level after increment post Ambient change is mismatched",
425 Color.argb(DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[1], 0, 0, 0),
426 lightColorMap[LIGHT_ID],
427 )
428 }
429
430 @Test
431 fun testAmbientBacklightControl_decrementLevel_afterAmbientChange() {
432 setupController()
433 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
434 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
435 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
436 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
437 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
438 sendAmbientBacklightValue(254)
439 assertEquals(
440 "Light value should be changed to ambient provided value",
441 Color.argb(254, 0, 0, 0),
442 lightColorMap[LIGHT_ID],
443 )
444
445 decrementKeyboardBacklight(DEVICE_ID)
446
447 val numLevels = DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL.size
448 assertEquals(
449 "Light value for level after decrement post Ambient change is mismatched",
450 Color.argb(DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[numLevels - 2], 0, 0, 0),
451 lightColorMap[LIGHT_ID],
452 )
453 }
454
455 @Test
456 fun testAmbientBacklightControl_ambientChanges_afterManualChange() {
457 setupController()
458 val keyboardWithBacklight = createKeyboard(DEVICE_ID)
459 val keyboardBacklight = createLight(LIGHT_ID, Light.LIGHT_TYPE_KEYBOARD_BACKLIGHT)
460 `when`(inputManagerRule.mock.getInputDevice(DEVICE_ID)).thenReturn(keyboardWithBacklight)
461 `when`(inputManagerRule.mock.getLights(DEVICE_ID)).thenReturn(listOf(keyboardBacklight))
462 keyboardBacklightController.onInputDeviceAdded(DEVICE_ID)
463 incrementKeyboardBacklight(DEVICE_ID)
464 assertEquals(
465 "Light value should be changed to the first level",
466 Color.argb(DEFAULT_BRIGHTNESS_VALUE_FOR_LEVEL[1], 0, 0, 0),
467 lightColorMap[LIGHT_ID],
468 )
469
470 sendAmbientBacklightValue(100)
471 assertNotEquals(
472 "Light value should not change based on ambient changes after manual changes",
473 Color.argb(100, 0, 0, 0),
474 lightColorMap[LIGHT_ID],
475 )
476 }
477
478 private fun assertIncrementDecrementForLevels(
479 device: InputDevice,
480 light: Light,
481 expectedLevels: IntArray,
482 ) {
483 val deviceId = device.id
484 val lightId = light.id
485 for (level in 1 until expectedLevels.size) {
486 incrementKeyboardBacklight(deviceId)
487 assertEquals(
488 "Light value for level $level mismatched",
489 Color.argb(expectedLevels[level], 0, 0, 0),
490 lightColorMap[lightId],
491 )
492 }
493
494 // Increment above max level
495 incrementKeyboardBacklight(deviceId)
496 assertEquals(
497 "Light value for max level mismatched",
498 Color.argb(MAX_BRIGHTNESS, 0, 0, 0),
499 lightColorMap[lightId],
500 )
501
502 for (level in expectedLevels.size - 2 downTo 0) {
503 decrementKeyboardBacklight(deviceId)
504 assertEquals(
505 "Light value for level $level mismatched",
506 Color.argb(expectedLevels[level], 0, 0, 0),
507 lightColorMap[lightId],
508 )
509 }
510
511 // Decrement below min level
512 decrementKeyboardBacklight(deviceId)
513 assertEquals(
514 "Light value for min level mismatched",
515 Color.argb(0, 0, 0, 0),
516 lightColorMap[lightId],
517 )
518 }
519
520 inner class KeyboardBacklightListener : IKeyboardBacklightListener.Stub() {
521 override fun onBrightnessChanged(
522 deviceId: Int,
523 state: IKeyboardBacklightState,
524 isTriggeredByKeyPress: Boolean,
525 ) {
526 lastBacklightState =
527 KeyboardBacklightState(
528 deviceId,
529 state.brightnessLevel,
530 state.maxBrightnessLevel,
531 isTriggeredByKeyPress,
532 )
533 }
534 }
535
536 private fun incrementKeyboardBacklight(deviceId: Int) {
537 keyboardBacklightController.incrementKeyboardBacklight(deviceId)
538 keyboardBacklightController.notifyUserActivity()
539 testLooper.dispatchAll()
540 }
541
542 private fun decrementKeyboardBacklight(deviceId: Int) {
543 keyboardBacklightController.decrementKeyboardBacklight(deviceId)
544 keyboardBacklightController.notifyUserActivity()
545 testLooper.dispatchAll()
546 }
547
548 private fun sendAmbientBacklightValue(brightnessValue: Int) {
549 keyboardBacklightController.handleAmbientLightValueChanged(brightnessValue)
550 keyboardBacklightController.notifyUserActivity()
551 testLooper.dispatchAll()
552 }
553
554 class KeyboardBacklightState(
555 val deviceId: Int,
556 val brightnessLevel: Int,
557 val maxBrightnessLevel: Int,
558 val isTriggeredByKeyPress: Boolean,
559 )
560
561 private inner class FakeAnimatorFactory : KeyboardBacklightController.AnimatorFactory {
562 override fun makeIntAnimator(from: Int, to: Int): ValueAnimator {
563 lastAnimationValues[0] = from
564 lastAnimationValues[1] = to
565 return ValueAnimator.ofInt(from, to)
566 }
567 }
568 }
569