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