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.systemui.dreams.touch; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyBoolean; 23 import static org.mockito.ArgumentMatchers.anyInt; 24 import static org.mockito.ArgumentMatchers.eq; 25 import static org.mockito.Mockito.doAnswer; 26 import static org.mockito.Mockito.never; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.graphics.Rect; 31 import android.graphics.Region; 32 import android.testing.AndroidTestingRunner; 33 import android.util.Pair; 34 import android.view.GestureDetector; 35 import android.view.InputEvent; 36 import android.view.MotionEvent; 37 38 import androidx.lifecycle.DefaultLifecycleObserver; 39 import androidx.lifecycle.Lifecycle; 40 import androidx.lifecycle.LifecycleObserver; 41 import androidx.lifecycle.LifecycleOwner; 42 import androidx.test.filters.SmallTest; 43 44 import com.android.systemui.SysuiTestCase; 45 import com.android.systemui.dreams.touch.dagger.InputSessionComponent; 46 import com.android.systemui.shared.system.InputChannelCompat; 47 import com.android.systemui.util.concurrency.FakeExecutor; 48 import com.android.systemui.util.display.DisplayHelper; 49 import com.android.systemui.util.time.FakeSystemClock; 50 51 import com.google.common.util.concurrent.ListenableFuture; 52 53 import org.junit.Before; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.mockito.ArgumentCaptor; 57 import org.mockito.Mockito; 58 import org.mockito.MockitoAnnotations; 59 60 import java.util.HashSet; 61 import java.util.Set; 62 import java.util.concurrent.ExecutionException; 63 import java.util.function.Consumer; 64 import java.util.stream.Collectors; 65 import java.util.stream.Stream; 66 67 @SmallTest 68 @RunWith(AndroidTestingRunner.class) 69 public class DreamOverlayTouchMonitorTest extends SysuiTestCase { 70 @Before setup()71 public void setup() { 72 MockitoAnnotations.initMocks(this); 73 } 74 75 private static class Environment { 76 private final InputSessionComponent.Factory mInputFactory; 77 private final InputSession mInputSession; 78 private final Lifecycle mLifecycle; 79 private final LifecycleOwner mLifecycleOwner; 80 private final DreamOverlayTouchMonitor mMonitor; 81 private final DefaultLifecycleObserver mLifecycleObserver; 82 private final InputChannelCompat.InputEventListener mEventListener; 83 private final GestureDetector.OnGestureListener mGestureListener; 84 private final DisplayHelper mDisplayHelper; 85 private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); 86 private final Rect mDisplayBounds = Mockito.mock(Rect.class); 87 Environment(Set<DreamTouchHandler> handlers)88 Environment(Set<DreamTouchHandler> handlers) { 89 mLifecycle = Mockito.mock(Lifecycle.class); 90 mLifecycleOwner = Mockito.mock(LifecycleOwner.class); 91 92 mInputFactory = Mockito.mock(InputSessionComponent.Factory.class); 93 final InputSessionComponent inputComponent = Mockito.mock(InputSessionComponent.class); 94 mInputSession = Mockito.mock(InputSession.class); 95 96 when(mInputFactory.create(any(), any(), any(), anyBoolean())) 97 .thenReturn(inputComponent); 98 when(inputComponent.getInputSession()).thenReturn(mInputSession); 99 100 mDisplayHelper = Mockito.mock(DisplayHelper.class); 101 when(mDisplayHelper.getMaxBounds(anyInt(), anyInt())) 102 .thenReturn(mDisplayBounds); 103 mMonitor = new DreamOverlayTouchMonitor(mExecutor, mLifecycle, mInputFactory, 104 mDisplayHelper, handlers); 105 mMonitor.init(); 106 107 final ArgumentCaptor<LifecycleObserver> lifecycleObserverCaptor = 108 ArgumentCaptor.forClass(LifecycleObserver.class); 109 verify(mLifecycle).addObserver(lifecycleObserverCaptor.capture()); 110 assertThat(lifecycleObserverCaptor.getValue() instanceof DefaultLifecycleObserver) 111 .isTrue(); 112 mLifecycleObserver = (DefaultLifecycleObserver) lifecycleObserverCaptor.getValue(); 113 114 updateLifecycle(observer -> observer.first.onResume(observer.second)); 115 116 // Capture creation request. 117 final ArgumentCaptor<InputChannelCompat.InputEventListener> inputEventListenerCaptor = 118 ArgumentCaptor.forClass(InputChannelCompat.InputEventListener.class); 119 final ArgumentCaptor<GestureDetector.OnGestureListener> gestureListenerCaptor = 120 ArgumentCaptor.forClass(GestureDetector.OnGestureListener.class); 121 verify(mInputFactory).create(any(), inputEventListenerCaptor.capture(), 122 gestureListenerCaptor.capture(), 123 eq(true)); 124 mEventListener = inputEventListenerCaptor.getValue(); 125 mGestureListener = gestureListenerCaptor.getValue(); 126 } 127 getDisplayBounds()128 public Rect getDisplayBounds() { 129 return mDisplayBounds; 130 } 131 executeAll()132 void executeAll() { 133 mExecutor.runAllReady(); 134 } 135 publishInputEvent(InputEvent event)136 void publishInputEvent(InputEvent event) { 137 mEventListener.onInputEvent(event); 138 } 139 publishGestureEvent(Consumer<GestureDetector.OnGestureListener> listenerConsumer)140 void publishGestureEvent(Consumer<GestureDetector.OnGestureListener> listenerConsumer) { 141 listenerConsumer.accept(mGestureListener); 142 } 143 updateLifecycle(Consumer<Pair<DefaultLifecycleObserver, LifecycleOwner>> consumer)144 void updateLifecycle(Consumer<Pair<DefaultLifecycleObserver, LifecycleOwner>> consumer) { 145 consumer.accept(Pair.create(mLifecycleObserver, mLifecycleOwner)); 146 } 147 verifyInputSessionDispose()148 void verifyInputSessionDispose() { 149 verify(mInputSession).dispose(); 150 Mockito.clearInvocations(mInputSession); 151 } 152 } 153 154 @Test testReportedDisplayBounds()155 public void testReportedDisplayBounds() { 156 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 157 final Environment environment = new Environment(Stream.of(touchHandler) 158 .collect(Collectors.toCollection(HashSet::new))); 159 160 final MotionEvent initialEvent = Mockito.mock(MotionEvent.class); 161 when(initialEvent.getX()).thenReturn(0.0f); 162 when(initialEvent.getY()).thenReturn(0.0f); 163 environment.publishInputEvent(initialEvent); 164 165 // Verify display bounds passed into TouchHandler#getTouchInitiationRegion 166 verify(touchHandler).getTouchInitiationRegion(eq(environment.getDisplayBounds()), any()); 167 final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor = 168 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 169 verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture()); 170 171 // Verify that display bounds provided from TouchSession#getBounds 172 assertThat(touchSessionArgumentCaptor.getValue().getBounds()) 173 .isEqualTo(environment.getDisplayBounds()); 174 } 175 176 @Test testEntryTouchZone()177 public void testEntryTouchZone() { 178 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 179 final Rect touchArea = new Rect(4, 4, 8 , 8); 180 181 doAnswer(invocation -> { 182 final Region region = (Region) invocation.getArguments()[1]; 183 region.set(touchArea); 184 return null; 185 }).when(touchHandler).getTouchInitiationRegion(any(), any()); 186 187 final Environment environment = new Environment(Stream.of(touchHandler) 188 .collect(Collectors.toCollection(HashSet::new))); 189 190 // Ensure touch outside specified region is not delivered. 191 final MotionEvent initialEvent = Mockito.mock(MotionEvent.class); 192 when(initialEvent.getX()).thenReturn(0.0f); 193 when(initialEvent.getY()).thenReturn(1.0f); 194 environment.publishInputEvent(initialEvent); 195 verify(touchHandler, never()).onSessionStart(any()); 196 197 // Make sure touch inside region causes session start. 198 when(initialEvent.getX()).thenReturn(5.0f); 199 when(initialEvent.getY()).thenReturn(5.0f); 200 environment.publishInputEvent(initialEvent); 201 verify(touchHandler).onSessionStart(any()); 202 } 203 204 @Test testSessionCount()205 public void testSessionCount() { 206 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 207 final Rect touchArea = new Rect(4, 4, 8 , 8); 208 209 final DreamTouchHandler unzonedTouchHandler = Mockito.mock(DreamTouchHandler.class); 210 doAnswer(invocation -> { 211 final Region region = (Region) invocation.getArguments()[1]; 212 region.set(touchArea); 213 return null; 214 }).when(touchHandler).getTouchInitiationRegion(any(), any()); 215 216 final Environment environment = new Environment(Stream.of(touchHandler, unzonedTouchHandler) 217 .collect(Collectors.toCollection(HashSet::new))); 218 219 // Ensure touch outside specified region is delivered to unzoned touch handler. 220 final MotionEvent initialEvent = Mockito.mock(MotionEvent.class); 221 when(initialEvent.getX()).thenReturn(0.0f); 222 when(initialEvent.getY()).thenReturn(1.0f); 223 environment.publishInputEvent(initialEvent); 224 225 ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionCaptor = ArgumentCaptor.forClass( 226 DreamTouchHandler.TouchSession.class); 227 228 // Make sure only one active session. 229 { 230 verify(unzonedTouchHandler).onSessionStart(touchSessionCaptor.capture()); 231 final DreamTouchHandler.TouchSession touchSession = touchSessionCaptor.getValue(); 232 assertThat(touchSession.getActiveSessionCount()).isEqualTo(1); 233 touchSession.pop(); 234 environment.executeAll(); 235 } 236 237 // Make sure touch inside the touch region. 238 when(initialEvent.getX()).thenReturn(5.0f); 239 when(initialEvent.getY()).thenReturn(5.0f); 240 environment.publishInputEvent(initialEvent); 241 242 // Make sure there are two active sessions. 243 { 244 verify(touchHandler).onSessionStart(touchSessionCaptor.capture()); 245 final DreamTouchHandler.TouchSession touchSession = touchSessionCaptor.getValue(); 246 assertThat(touchSession.getActiveSessionCount()).isEqualTo(2); 247 touchSession.pop(); 248 } 249 } 250 251 @Test testInputEventPropagation()252 public void testInputEventPropagation() { 253 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 254 255 final Environment environment = new Environment(Stream.of(touchHandler) 256 .collect(Collectors.toCollection(HashSet::new))); 257 258 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 259 environment.publishInputEvent(initialEvent); 260 261 // Ensure session started 262 final InputChannelCompat.InputEventListener eventListener = 263 registerInputEventListener(touchHandler); 264 265 // First event will be missed since we register after the execution loop, 266 final InputEvent event = Mockito.mock(InputEvent.class); 267 environment.publishInputEvent(event); 268 verify(eventListener).onInputEvent(eq(event)); 269 } 270 271 @Test testInputEventPropagationAfterRemoval()272 public void testInputEventPropagationAfterRemoval() { 273 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 274 275 final Environment environment = new Environment(Stream.of(touchHandler) 276 .collect(Collectors.toCollection(HashSet::new))); 277 278 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 279 environment.publishInputEvent(initialEvent); 280 281 // Ensure session started 282 final DreamTouchHandler.TouchSession session = captureSession(touchHandler); 283 final InputChannelCompat.InputEventListener eventListener = 284 registerInputEventListener(session); 285 286 session.pop(); 287 environment.executeAll(); 288 289 final InputEvent event = Mockito.mock(InputEvent.class); 290 environment.publishInputEvent(event); 291 292 verify(eventListener, never()).onInputEvent(eq(event)); 293 } 294 295 @Test testInputGesturePropagation()296 public void testInputGesturePropagation() { 297 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 298 299 final Environment environment = new Environment(Stream.of(touchHandler) 300 .collect(Collectors.toCollection(HashSet::new))); 301 302 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 303 environment.publishInputEvent(initialEvent); 304 305 // Ensure session started 306 final GestureDetector.OnGestureListener gestureListener = 307 registerGestureListener(touchHandler); 308 309 final MotionEvent event = Mockito.mock(MotionEvent.class); 310 environment.publishGestureEvent(onGestureListener -> onGestureListener.onShowPress(event)); 311 verify(gestureListener).onShowPress(eq(event)); 312 } 313 314 @Test testGestureConsumption()315 public void testGestureConsumption() { 316 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 317 318 final Environment environment = new Environment(Stream.of(touchHandler) 319 .collect(Collectors.toCollection(HashSet::new))); 320 321 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 322 environment.publishInputEvent(initialEvent); 323 324 // Ensure session started 325 final GestureDetector.OnGestureListener gestureListener = 326 registerGestureListener(touchHandler); 327 328 when(gestureListener.onDown(any())).thenReturn(true); 329 final MotionEvent event = Mockito.mock(MotionEvent.class); 330 environment.publishGestureEvent(onGestureListener -> { 331 assertThat(onGestureListener.onDown(event)).isTrue(); 332 }); 333 334 verify(gestureListener).onDown(eq(event)); 335 } 336 337 @Test testBroadcast()338 public void testBroadcast() { 339 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 340 final DreamTouchHandler touchHandler2 = Mockito.mock(DreamTouchHandler.class); 341 342 final Environment environment = new Environment(Stream.of(touchHandler, touchHandler2) 343 .collect(Collectors.toCollection(HashSet::new))); 344 345 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 346 environment.publishInputEvent(initialEvent); 347 348 final HashSet<InputChannelCompat.InputEventListener> inputListeners = new HashSet<>(); 349 350 inputListeners.add(registerInputEventListener(touchHandler)); 351 inputListeners.add(registerInputEventListener(touchHandler)); 352 inputListeners.add(registerInputEventListener(touchHandler2)); 353 354 final MotionEvent event = Mockito.mock(MotionEvent.class); 355 environment.publishInputEvent(event); 356 357 inputListeners 358 .stream() 359 .forEach(inputEventListener -> verify(inputEventListener).onInputEvent(event)); 360 } 361 362 @Test testPush()363 public void testPush() throws InterruptedException, ExecutionException { 364 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 365 366 final Environment environment = new Environment(Stream.of(touchHandler) 367 .collect(Collectors.toCollection(HashSet::new))); 368 369 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 370 environment.publishInputEvent(initialEvent); 371 372 final DreamTouchHandler.TouchSession session = captureSession(touchHandler); 373 final InputChannelCompat.InputEventListener eventListener = 374 registerInputEventListener(session); 375 376 final ListenableFuture<DreamTouchHandler.TouchSession> frontSessionFuture = session.push(); 377 environment.executeAll(); 378 final DreamTouchHandler.TouchSession frontSession = frontSessionFuture.get(); 379 final InputChannelCompat.InputEventListener frontEventListener = 380 registerInputEventListener(frontSession); 381 382 final MotionEvent event = Mockito.mock(MotionEvent.class); 383 environment.publishInputEvent(event); 384 385 verify(frontEventListener).onInputEvent(eq(event)); 386 verify(eventListener, never()).onInputEvent(any()); 387 388 Mockito.clearInvocations(eventListener, frontEventListener); 389 390 ListenableFuture<DreamTouchHandler.TouchSession> sessionFuture = frontSession.pop(); 391 environment.executeAll(); 392 393 DreamTouchHandler.TouchSession returnedSession = sessionFuture.get(); 394 assertThat(session == returnedSession).isTrue(); 395 396 environment.executeAll(); 397 398 final MotionEvent followupEvent = Mockito.mock(MotionEvent.class); 399 environment.publishInputEvent(followupEvent); 400 401 verify(eventListener).onInputEvent(eq(followupEvent)); 402 verify(frontEventListener, never()).onInputEvent(any()); 403 } 404 405 @Test testPop()406 public void testPop() { 407 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 408 final DreamTouchHandler.TouchSession.Callback callback = 409 Mockito.mock(DreamTouchHandler.TouchSession.Callback.class); 410 411 final Environment environment = new Environment(Stream.of(touchHandler) 412 .collect(Collectors.toCollection(HashSet::new))); 413 414 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 415 environment.publishInputEvent(initialEvent); 416 417 final DreamTouchHandler.TouchSession session = captureSession(touchHandler); 418 session.registerCallback(callback); 419 session.pop(); 420 environment.executeAll(); 421 422 verify(callback).onRemoved(); 423 } 424 425 @Test testPauseWithNoActiveSessions()426 public void testPauseWithNoActiveSessions() { 427 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 428 429 final Environment environment = new Environment(Stream.of(touchHandler) 430 .collect(Collectors.toCollection(HashSet::new))); 431 432 environment.updateLifecycle(observerOwnerPair -> { 433 observerOwnerPair.first.onPause(observerOwnerPair.second); 434 }); 435 436 environment.verifyInputSessionDispose(); 437 } 438 439 @Test testDeferredPauseWithActiveSessions()440 public void testDeferredPauseWithActiveSessions() { 441 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 442 443 final Environment environment = new Environment(Stream.of(touchHandler) 444 .collect(Collectors.toCollection(HashSet::new))); 445 446 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 447 environment.publishInputEvent(initialEvent); 448 449 // Ensure session started 450 final InputChannelCompat.InputEventListener eventListener = 451 registerInputEventListener(touchHandler); 452 453 // First event will be missed since we register after the execution loop, 454 final InputEvent event = Mockito.mock(InputEvent.class); 455 environment.publishInputEvent(event); 456 verify(eventListener).onInputEvent(eq(event)); 457 458 final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor = 459 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 460 461 verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture()); 462 463 environment.updateLifecycle(observerOwnerPair -> { 464 observerOwnerPair.first.onPause(observerOwnerPair.second); 465 }); 466 467 verify(environment.mInputSession, never()).dispose(); 468 469 // End session 470 touchSessionArgumentCaptor.getValue().pop(); 471 environment.executeAll(); 472 473 // Check to make sure the input session is now disposed. 474 environment.verifyInputSessionDispose(); 475 } 476 477 @Test testDestroyWithActiveSessions()478 public void testDestroyWithActiveSessions() { 479 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 480 481 final Environment environment = new Environment(Stream.of(touchHandler) 482 .collect(Collectors.toCollection(HashSet::new))); 483 484 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 485 environment.publishInputEvent(initialEvent); 486 487 // Ensure session started 488 final InputChannelCompat.InputEventListener eventListener = 489 registerInputEventListener(touchHandler); 490 491 // First event will be missed since we register after the execution loop, 492 final InputEvent event = Mockito.mock(InputEvent.class); 493 environment.publishInputEvent(event); 494 verify(eventListener).onInputEvent(eq(event)); 495 496 final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor = 497 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 498 499 verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture()); 500 501 environment.updateLifecycle(observerOwnerPair -> { 502 observerOwnerPair.first.onDestroy(observerOwnerPair.second); 503 }); 504 505 // Check to make sure the input session is now disposed. 506 environment.verifyInputSessionDispose(); 507 } 508 509 510 @Test testPilfering()511 public void testPilfering() { 512 final DreamTouchHandler touchHandler1 = Mockito.mock(DreamTouchHandler.class); 513 final DreamTouchHandler touchHandler2 = Mockito.mock(DreamTouchHandler.class); 514 515 final Environment environment = new Environment(Stream.of(touchHandler1, touchHandler2) 516 .collect(Collectors.toCollection(HashSet::new))); 517 518 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 519 environment.publishInputEvent(initialEvent); 520 521 final DreamTouchHandler.TouchSession session1 = captureSession(touchHandler1); 522 final GestureDetector.OnGestureListener gestureListener1 = 523 registerGestureListener(session1); 524 525 final DreamTouchHandler.TouchSession session2 = captureSession(touchHandler2); 526 final GestureDetector.OnGestureListener gestureListener2 = 527 registerGestureListener(session2); 528 when(gestureListener2.onDown(any())).thenReturn(true); 529 530 final MotionEvent gestureEvent = Mockito.mock(MotionEvent.class); 531 environment.publishGestureEvent( 532 onGestureListener -> onGestureListener.onDown(gestureEvent)); 533 534 Mockito.clearInvocations(gestureListener1, gestureListener2); 535 536 final MotionEvent followupEvent = Mockito.mock(MotionEvent.class); 537 environment.publishGestureEvent( 538 onGestureListener -> onGestureListener.onDown(followupEvent)); 539 540 verify(gestureListener1, never()).onDown(any()); 541 verify(gestureListener2).onDown(eq(followupEvent)); 542 } 543 544 @Test testOnRemovedCallbackOnStopMonitoring()545 public void testOnRemovedCallbackOnStopMonitoring() { 546 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 547 final DreamTouchHandler.TouchSession.Callback callback = 548 Mockito.mock(DreamTouchHandler.TouchSession.Callback.class); 549 550 final Environment environment = new Environment(Stream.of(touchHandler) 551 .collect(Collectors.toCollection(HashSet::new))); 552 553 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 554 environment.publishInputEvent(initialEvent); 555 556 final DreamTouchHandler.TouchSession session = captureSession(touchHandler); 557 session.registerCallback(callback); 558 559 environment.executeAll(); 560 561 environment.updateLifecycle(observerOwnerPair -> { 562 observerOwnerPair.first.onDestroy(observerOwnerPair.second); 563 }); 564 565 environment.executeAll(); 566 567 verify(callback).onRemoved(); 568 } 569 registerGestureListener(DreamTouchHandler handler)570 public GestureDetector.OnGestureListener registerGestureListener(DreamTouchHandler handler) { 571 final GestureDetector.OnGestureListener gestureListener = Mockito.mock( 572 GestureDetector.OnGestureListener.class); 573 final ArgumentCaptor<DreamTouchHandler.TouchSession> sessionCaptor = 574 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 575 verify(handler).onSessionStart(sessionCaptor.capture()); 576 sessionCaptor.getValue().registerGestureListener(gestureListener); 577 578 return gestureListener; 579 } 580 registerGestureListener( DreamTouchHandler.TouchSession session)581 public GestureDetector.OnGestureListener registerGestureListener( 582 DreamTouchHandler.TouchSession session) { 583 final GestureDetector.OnGestureListener gestureListener = Mockito.mock( 584 GestureDetector.OnGestureListener.class); 585 session.registerGestureListener(gestureListener); 586 587 return gestureListener; 588 } 589 registerInputEventListener( DreamTouchHandler.TouchSession session)590 public InputChannelCompat.InputEventListener registerInputEventListener( 591 DreamTouchHandler.TouchSession session) { 592 final InputChannelCompat.InputEventListener eventListener = Mockito.mock( 593 InputChannelCompat.InputEventListener.class); 594 session.registerInputListener(eventListener); 595 596 return eventListener; 597 } 598 captureSession(DreamTouchHandler handler)599 public DreamTouchHandler.TouchSession captureSession(DreamTouchHandler handler) { 600 final ArgumentCaptor<DreamTouchHandler.TouchSession> sessionCaptor = 601 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 602 verify(handler).onSessionStart(sessionCaptor.capture()); 603 return sessionCaptor.getValue(); 604 } 605 registerInputEventListener( DreamTouchHandler handler)606 public InputChannelCompat.InputEventListener registerInputEventListener( 607 DreamTouchHandler handler) { 608 return registerInputEventListener(captureSession(handler)); 609 } 610 } 611