1 /* <lambda>null2 * 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 package com.android.systemui.stylus 17 18 import android.bluetooth.BluetoothAdapter 19 import android.bluetooth.BluetoothDevice 20 import android.hardware.BatteryState 21 import android.hardware.input.InputManager 22 import android.hardware.input.InputSettings 23 import android.os.Handler 24 import android.testing.AndroidTestingRunner 25 import android.view.InputDevice 26 import androidx.test.filters.SmallTest 27 import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession 28 import com.android.dx.mockito.inline.extended.ExtendedMockito.never 29 import com.android.dx.mockito.inline.extended.ExtendedMockito.times 30 import com.android.dx.mockito.inline.extended.ExtendedMockito.verify 31 import com.android.dx.mockito.inline.extended.StaticMockitoSession 32 import com.android.internal.logging.InstanceId 33 import com.android.internal.logging.UiEventLogger 34 import com.android.systemui.InstanceIdSequenceFake 35 import com.android.systemui.SysuiTestCase 36 import com.android.systemui.flags.FeatureFlags 37 import com.android.systemui.flags.Flags 38 import com.android.systemui.util.mockito.any 39 import com.android.systemui.util.mockito.whenever 40 import java.util.concurrent.Executor 41 import org.junit.After 42 import org.junit.Before 43 import org.junit.Test 44 import org.junit.runner.RunWith 45 import org.mockito.Mock 46 import org.mockito.Mockito.clearInvocations 47 import org.mockito.Mockito.inOrder 48 import org.mockito.Mockito.verifyNoMoreInteractions 49 import org.mockito.Mockito.verifyZeroInteractions 50 import org.mockito.MockitoAnnotations 51 import org.mockito.quality.Strictness 52 53 @RunWith(AndroidTestingRunner::class) 54 @SmallTest 55 class StylusManagerTest : SysuiTestCase() { 56 @Mock lateinit var inputManager: InputManager 57 @Mock lateinit var stylusDevice: InputDevice 58 @Mock lateinit var btStylusDevice: InputDevice 59 @Mock lateinit var otherDevice: InputDevice 60 @Mock lateinit var batteryState: BatteryState 61 @Mock lateinit var bluetoothAdapter: BluetoothAdapter 62 @Mock lateinit var bluetoothDevice: BluetoothDevice 63 @Mock lateinit var handler: Handler 64 @Mock lateinit var featureFlags: FeatureFlags 65 @Mock lateinit var uiEventLogger: UiEventLogger 66 @Mock lateinit var stylusCallback: StylusManager.StylusCallback 67 @Mock lateinit var otherStylusCallback: StylusManager.StylusCallback 68 69 private lateinit var mockitoSession: StaticMockitoSession 70 private lateinit var stylusManager: StylusManager 71 private val instanceIdSequenceFake = InstanceIdSequenceFake(10) 72 73 @Before 74 fun setUp() { 75 MockitoAnnotations.initMocks(this) 76 mockitoSession = 77 mockitoSession() 78 .mockStatic(InputSettings::class.java) 79 .strictness(Strictness.LENIENT) 80 .startMocking() 81 82 whenever(handler.post(any())).thenAnswer { 83 (it.arguments[0] as Runnable).run() 84 true 85 } 86 87 stylusManager = 88 StylusManager( 89 mContext, 90 inputManager, 91 bluetoothAdapter, 92 handler, 93 EXECUTOR, 94 featureFlags, 95 uiEventLogger 96 ) 97 98 stylusManager.instanceIdSequence = instanceIdSequenceFake 99 100 whenever(otherDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(false) 101 whenever(stylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true) 102 whenever(btStylusDevice.supportsSource(InputDevice.SOURCE_STYLUS)).thenReturn(true) 103 104 whenever(btStylusDevice.isExternal).thenReturn(true) 105 106 whenever(stylusDevice.bluetoothAddress).thenReturn(null) 107 whenever(btStylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS) 108 109 whenever(btStylusDevice.batteryState).thenReturn(batteryState) 110 whenever(stylusDevice.batteryState).thenReturn(batteryState) 111 whenever(batteryState.capacity).thenReturn(0.5f) 112 113 whenever(inputManager.getInputDevice(OTHER_DEVICE_ID)).thenReturn(otherDevice) 114 whenever(inputManager.getInputDevice(STYLUS_DEVICE_ID)).thenReturn(stylusDevice) 115 whenever(inputManager.getInputDevice(BT_STYLUS_DEVICE_ID)).thenReturn(btStylusDevice) 116 whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(STYLUS_DEVICE_ID)) 117 118 whenever(bluetoothAdapter.getRemoteDevice(STYLUS_BT_ADDRESS)).thenReturn(bluetoothDevice) 119 whenever(bluetoothDevice.address).thenReturn(STYLUS_BT_ADDRESS) 120 121 whenever(featureFlags.isEnabled(Flags.TRACK_STYLUS_EVER_USED)).thenReturn(true) 122 123 whenever(InputSettings.isStylusEverUsed(mContext)).thenReturn(false) 124 125 stylusManager.startListener() 126 stylusManager.registerCallback(stylusCallback) 127 clearInvocations(inputManager) 128 } 129 130 @After 131 fun tearDown() { 132 mockitoSession.finishMocking() 133 } 134 135 @Test 136 fun startListener_hasNotStarted_registersInputDeviceListener() { 137 stylusManager = 138 StylusManager( 139 mContext, 140 inputManager, 141 bluetoothAdapter, 142 handler, 143 EXECUTOR, 144 featureFlags, 145 uiEventLogger 146 ) 147 148 stylusManager.startListener() 149 150 verify(inputManager, times(1)).registerInputDeviceListener(any(), any()) 151 } 152 153 @Test 154 fun startListener_hasNotStarted_registersExistingBluetoothDevice() { 155 whenever(inputManager.inputDeviceIds).thenReturn(intArrayOf(BT_STYLUS_DEVICE_ID)) 156 157 stylusManager = 158 StylusManager( 159 mContext, 160 inputManager, 161 bluetoothAdapter, 162 handler, 163 EXECUTOR, 164 featureFlags, 165 uiEventLogger 166 ) 167 168 stylusManager.startListener() 169 170 verify(bluetoothAdapter, times(1)) 171 .addOnMetadataChangedListener(bluetoothDevice, EXECUTOR, stylusManager) 172 } 173 174 @Test 175 fun startListener_hasStarted_doesNothing() { 176 stylusManager.startListener() 177 178 verifyZeroInteractions(inputManager) 179 } 180 181 @Test 182 fun onInputDeviceAdded_hasNotStarted_doesNothing() { 183 stylusManager = 184 StylusManager( 185 mContext, 186 inputManager, 187 bluetoothAdapter, 188 handler, 189 EXECUTOR, 190 featureFlags, 191 uiEventLogger 192 ) 193 194 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 195 196 verifyZeroInteractions(stylusCallback) 197 } 198 199 @Test 200 fun onInputDeviceAdded_multipleRegisteredCallbacks_callsAll() { 201 stylusManager.registerCallback(otherStylusCallback) 202 203 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 204 205 verify(stylusCallback, times(1)).onStylusAdded(STYLUS_DEVICE_ID) 206 verifyNoMoreInteractions(stylusCallback) 207 verify(otherStylusCallback, times(1)).onStylusAdded(STYLUS_DEVICE_ID) 208 verifyNoMoreInteractions(otherStylusCallback) 209 } 210 211 @Test 212 fun onInputDeviceAdded_internalStylus_registersBatteryListener() { 213 whenever(stylusDevice.isExternal).thenReturn(false) 214 215 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 216 217 verify(inputManager, times(1)) 218 .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, EXECUTOR, stylusManager) 219 } 220 221 @Test 222 fun onInputDeviceAdded_externalStylus_doesNotRegisterbatteryListener() { 223 whenever(stylusDevice.isExternal).thenReturn(true) 224 225 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 226 227 verify(inputManager, never()) 228 .addInputDeviceBatteryListener(STYLUS_DEVICE_ID, EXECUTOR, stylusManager) 229 } 230 231 @Test 232 fun onInputDeviceAdded_stylus_callsCallbacksOnStylusAdded() { 233 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 234 235 verify(stylusCallback, times(1)).onStylusAdded(STYLUS_DEVICE_ID) 236 verifyNoMoreInteractions(stylusCallback) 237 } 238 239 @Test 240 fun onInputDeviceAdded_btStylus_firstUsed_callsCallbacksOnStylusFirstUsed() { 241 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 242 243 verify(stylusCallback, times(1)).onStylusFirstUsed() 244 } 245 246 @Test 247 fun onInputDeviceAdded_btStylus_firstUsed_setsFlag() { 248 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 249 verify({ InputSettings.setStylusEverUsed(mContext, true) }, times(1)) 250 } 251 252 @Test 253 fun onInputDeviceAdded_btStylus_callsCallbacksWithAddress() { 254 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 255 256 inOrder(stylusCallback).let { 257 it.verify(stylusCallback, times(1)).onStylusAdded(BT_STYLUS_DEVICE_ID) 258 it.verify(stylusCallback, times(1)) 259 .onStylusBluetoothConnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS) 260 } 261 } 262 263 @Test 264 fun onInputDeviceAdded_notStylus_doesNotCallCallbacks() { 265 stylusManager.onInputDeviceAdded(OTHER_DEVICE_ID) 266 267 verifyNoMoreInteractions(stylusCallback) 268 } 269 270 @Test 271 fun onInputDeviceChanged_hasNotStarted_doesNothing() { 272 stylusManager = 273 StylusManager( 274 mContext, 275 inputManager, 276 bluetoothAdapter, 277 handler, 278 EXECUTOR, 279 featureFlags, 280 uiEventLogger 281 ) 282 283 stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID) 284 285 verifyZeroInteractions(stylusCallback) 286 } 287 288 @Test 289 fun onInputDeviceChanged_multipleRegisteredCallbacks_callsAll() { 290 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 291 whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS) 292 stylusManager.registerCallback(otherStylusCallback) 293 294 stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID) 295 296 verify(stylusCallback, times(1)) 297 .onStylusBluetoothConnected(STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS) 298 verify(otherStylusCallback, times(1)) 299 .onStylusBluetoothConnected(STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS) 300 } 301 302 @Test 303 fun onInputDeviceChanged_stylusNewBtConnection_callsCallbacks() { 304 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 305 whenever(stylusDevice.bluetoothAddress).thenReturn(STYLUS_BT_ADDRESS) 306 307 stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID) 308 309 verify(stylusCallback, times(1)) 310 .onStylusBluetoothConnected(STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS) 311 } 312 313 @Test 314 fun onInputDeviceChanged_stylusLostBtConnection_callsCallbacks() { 315 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 316 whenever(btStylusDevice.bluetoothAddress).thenReturn(null) 317 318 stylusManager.onInputDeviceChanged(BT_STYLUS_DEVICE_ID) 319 320 verify(stylusCallback, times(1)) 321 .onStylusBluetoothDisconnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS) 322 } 323 324 @Test 325 fun onInputDeviceChanged_btConnection_stylusAlreadyBtConnected_onlyCallsListenersOnce() { 326 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 327 328 stylusManager.onInputDeviceChanged(BT_STYLUS_DEVICE_ID) 329 330 verify(stylusCallback, times(1)) 331 .onStylusBluetoothConnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS) 332 } 333 334 @Test 335 fun onInputDeviceChanged_noBtConnection_stylusNeverBtConnected_doesNotCallCallbacks() { 336 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 337 338 stylusManager.onInputDeviceChanged(STYLUS_DEVICE_ID) 339 340 verify(stylusCallback, never()).onStylusBluetoothDisconnected(any(), any()) 341 } 342 343 @Test 344 fun onInputDeviceRemoved_hasNotStarted_doesNothing() { 345 stylusManager = 346 StylusManager( 347 mContext, 348 inputManager, 349 bluetoothAdapter, 350 handler, 351 EXECUTOR, 352 featureFlags, 353 uiEventLogger 354 ) 355 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 356 357 stylusManager.onInputDeviceRemoved(STYLUS_DEVICE_ID) 358 359 verifyZeroInteractions(stylusCallback) 360 } 361 362 @Test 363 fun onInputDeviceRemoved_multipleRegisteredCallbacks_callsAll() { 364 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 365 stylusManager.registerCallback(otherStylusCallback) 366 367 stylusManager.onInputDeviceRemoved(STYLUS_DEVICE_ID) 368 369 verify(stylusCallback, times(1)).onStylusRemoved(STYLUS_DEVICE_ID) 370 verify(otherStylusCallback, times(1)).onStylusRemoved(STYLUS_DEVICE_ID) 371 } 372 373 @Test 374 fun onInputDeviceRemoved_stylus_callsCallbacks() { 375 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 376 377 stylusManager.onInputDeviceRemoved(STYLUS_DEVICE_ID) 378 379 verify(stylusCallback, times(1)).onStylusRemoved(STYLUS_DEVICE_ID) 380 verify(stylusCallback, never()).onStylusBluetoothDisconnected(any(), any()) 381 } 382 383 @Test 384 fun onInputDeviceRemoved_unregistersBatteryListener() { 385 stylusManager.onInputDeviceAdded(STYLUS_DEVICE_ID) 386 387 stylusManager.onInputDeviceRemoved(STYLUS_DEVICE_ID) 388 389 verify(inputManager, times(1)) 390 .removeInputDeviceBatteryListener(STYLUS_DEVICE_ID, stylusManager) 391 } 392 393 @Test 394 fun onInputDeviceRemoved_btStylus_callsCallbacks() { 395 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 396 397 stylusManager.onInputDeviceRemoved(BT_STYLUS_DEVICE_ID) 398 399 inOrder(stylusCallback).let { 400 it.verify(stylusCallback, times(1)) 401 .onStylusBluetoothDisconnected(BT_STYLUS_DEVICE_ID, STYLUS_BT_ADDRESS) 402 it.verify(stylusCallback, times(1)).onStylusRemoved(BT_STYLUS_DEVICE_ID) 403 } 404 } 405 406 @Test 407 fun onStylusBluetoothConnected_registersMetadataListener() { 408 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 409 410 verify(bluetoothAdapter, times(1)).addOnMetadataChangedListener(any(), any(), any()) 411 } 412 413 @Test 414 fun onStylusBluetoothConnected_noBluetoothDevice_doesNotRegisterMetadataListener() { 415 whenever(bluetoothAdapter.getRemoteDevice(STYLUS_BT_ADDRESS)).thenReturn(null) 416 417 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 418 419 verify(bluetoothAdapter, never()).addOnMetadataChangedListener(any(), any(), any()) 420 } 421 422 @Test 423 fun onStylusBluetoothConnected_logsEvent() { 424 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 425 426 verify(uiEventLogger, times(1)) 427 .logWithInstanceId( 428 StylusUiEvent.BLUETOOTH_STYLUS_CONNECTED, 429 0, 430 null, 431 InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId) 432 ) 433 } 434 435 @Test 436 fun onStylusBluetoothDisconnected_unregistersMetadataListener() { 437 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 438 439 stylusManager.onInputDeviceRemoved(BT_STYLUS_DEVICE_ID) 440 441 verify(bluetoothAdapter, times(1)).removeOnMetadataChangedListener(any(), any()) 442 } 443 444 @Test 445 fun onStylusBluetoothDisconnected_logsEventInSameSession() { 446 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 447 val instanceId = InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId) 448 449 stylusManager.onInputDeviceRemoved(BT_STYLUS_DEVICE_ID) 450 451 verify(uiEventLogger, times(1)) 452 .logWithInstanceId(StylusUiEvent.BLUETOOTH_STYLUS_CONNECTED, 0, null, instanceId) 453 verify(uiEventLogger, times(1)) 454 .logWithInstanceId(StylusUiEvent.BLUETOOTH_STYLUS_DISCONNECTED, 0, null, instanceId) 455 } 456 457 @Test 458 fun onMetadataChanged_chargingStateTrue_executesBatteryCallbacks() { 459 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 460 461 stylusManager.onMetadataChanged( 462 bluetoothDevice, 463 BluetoothDevice.METADATA_MAIN_CHARGING, 464 "true".toByteArray() 465 ) 466 467 verify(stylusCallback, times(1)) 468 .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, true) 469 } 470 471 @Test 472 fun onMetadataChanged_chargingStateFalse_executesBatteryCallbacks() { 473 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 474 475 stylusManager.onMetadataChanged( 476 bluetoothDevice, 477 BluetoothDevice.METADATA_MAIN_CHARGING, 478 "false".toByteArray() 479 ) 480 481 verify(stylusCallback, times(1)) 482 .onStylusBluetoothChargingStateChanged(BT_STYLUS_DEVICE_ID, bluetoothDevice, false) 483 } 484 485 @Test 486 fun onMetadataChanged_chargingStateNoDevice_doesNotExecuteBatteryCallbacks() { 487 stylusManager.onMetadataChanged( 488 bluetoothDevice, 489 BluetoothDevice.METADATA_MAIN_CHARGING, 490 "true".toByteArray() 491 ) 492 493 verifyNoMoreInteractions(stylusCallback) 494 } 495 496 @Test 497 fun onMetadataChanged_notChargingState_doesNotExecuteBatteryCallbacks() { 498 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 499 500 stylusManager.onMetadataChanged( 501 bluetoothDevice, 502 BluetoothDevice.METADATA_DEVICE_TYPE, 503 "true".toByteArray() 504 ) 505 506 verify(stylusCallback, never()).onStylusBluetoothChargingStateChanged(any(), any(), any()) 507 } 508 509 @Test 510 fun onBatteryStateChanged_batteryPresent_stylusNeverUsed_updateEverUsedFlag() { 511 whenever(batteryState.isPresent).thenReturn(true) 512 513 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 514 515 verify({ InputSettings.setStylusEverUsed(mContext, true) }, times(1)) 516 } 517 518 @Test 519 fun onBatteryStateChanged_batteryPresent_stylusNeverUsed_executesStylusFirstUsed() { 520 whenever(batteryState.isPresent).thenReturn(true) 521 522 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 523 524 verify(stylusCallback, times(1)).onStylusFirstUsed() 525 } 526 527 @Test 528 fun onBatteryStateChanged_batteryPresent_notInUsiSession_logsSessionStart() { 529 whenever(batteryState.isPresent).thenReturn(true) 530 531 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 532 533 verify(uiEventLogger, times(1)) 534 .logWithInstanceIdAndPosition( 535 StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED, 536 0, 537 null, 538 InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId), 539 0, 540 ) 541 } 542 543 @Test 544 fun onBatteryStateChanged_batteryPresent_btStylusPresent_logsSessionStart() { 545 whenever(batteryState.isPresent).thenReturn(true) 546 stylusManager.onInputDeviceAdded(BT_STYLUS_DEVICE_ID) 547 548 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 549 550 verify(uiEventLogger, times(1)) 551 .logWithInstanceIdAndPosition( 552 StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED, 553 0, 554 null, 555 InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId), 556 1, 557 ) 558 } 559 560 @Test 561 fun onBatteryStateChanged_batteryPresent_inUsiSession_doesNotLogSessionStart() { 562 whenever(batteryState.isPresent).thenReturn(true) 563 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 564 clearInvocations(uiEventLogger) 565 566 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 567 568 verifyZeroInteractions(uiEventLogger) 569 } 570 571 @Test 572 fun onBatteryStateChanged_batteryAbsent_notInUsiSession_doesNotLogSessionEnd() { 573 whenever(batteryState.isPresent).thenReturn(false) 574 575 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 576 577 verifyZeroInteractions(uiEventLogger) 578 } 579 580 @Test 581 fun onBatteryStateChanged_batteryAbsent_inUsiSession_logSessionEnd() { 582 whenever(batteryState.isPresent).thenReturn(true) 583 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 584 val instanceId = InstanceId.fakeInstanceId(instanceIdSequenceFake.lastInstanceId) 585 whenever(batteryState.isPresent).thenReturn(false) 586 587 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 588 589 verify(uiEventLogger, times(1)) 590 .logWithInstanceIdAndPosition( 591 StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_FIRST_DETECTED, 592 0, 593 null, 594 instanceId, 595 0 596 ) 597 598 verify(uiEventLogger, times(1)) 599 .logWithInstanceIdAndPosition( 600 StylusUiEvent.USI_STYLUS_BATTERY_PRESENCE_REMOVED, 601 0, 602 null, 603 instanceId, 604 0 605 ) 606 } 607 608 @Test 609 fun onBatteryStateChanged_batteryPresent_stylusUsed_doesNotUpdateEverUsedFlag() { 610 whenever(InputSettings.isStylusEverUsed(mContext)).thenReturn(true) 611 612 whenever(batteryState.isPresent).thenReturn(true) 613 614 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 615 616 verify({ InputSettings.setStylusEverUsed(mContext, true) }, never()) 617 } 618 619 @Test 620 fun onBatteryStateChanged_batteryNotPresent_doesNotUpdateEverUsedFlag() { 621 whenever(batteryState.isPresent).thenReturn(false) 622 623 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 624 625 verify(inputManager, never()) 626 .removeInputDeviceBatteryListener(STYLUS_DEVICE_ID, stylusManager) 627 } 628 629 @Test 630 fun onBatteryStateChanged_hasNotStarted_doesNothing() { 631 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 632 633 verifyZeroInteractions(inputManager) 634 } 635 636 @Test 637 fun onBatteryStateChanged_executesBatteryCallbacks() { 638 stylusManager.onBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 639 640 verify(stylusCallback, times(1)) 641 .onStylusUsiBatteryStateChanged(STYLUS_DEVICE_ID, 1, batteryState) 642 } 643 644 companion object { 645 private val EXECUTOR = Executor { r -> r.run() } 646 647 private const val OTHER_DEVICE_ID = 0 648 private const val STYLUS_DEVICE_ID = 1 649 private const val BT_STYLUS_DEVICE_ID = 2 650 651 private const val STYLUS_BT_ADDRESS = "SOME:ADDRESS" 652 } 653 } 654