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 testInputGesturePropagation()272 public void testInputGesturePropagation() { 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 GestureDetector.OnGestureListener gestureListener = 283 registerGestureListener(touchHandler); 284 285 final MotionEvent event = Mockito.mock(MotionEvent.class); 286 environment.publishGestureEvent(onGestureListener -> onGestureListener.onShowPress(event)); 287 verify(gestureListener).onShowPress(eq(event)); 288 } 289 290 @Test testGestureConsumption()291 public void testGestureConsumption() { 292 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 293 294 final Environment environment = new Environment(Stream.of(touchHandler) 295 .collect(Collectors.toCollection(HashSet::new))); 296 297 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 298 environment.publishInputEvent(initialEvent); 299 300 // Ensure session started 301 final GestureDetector.OnGestureListener gestureListener = 302 registerGestureListener(touchHandler); 303 304 when(gestureListener.onDown(any())).thenReturn(true); 305 final MotionEvent event = Mockito.mock(MotionEvent.class); 306 environment.publishGestureEvent(onGestureListener -> { 307 assertThat(onGestureListener.onDown(event)).isTrue(); 308 }); 309 310 verify(gestureListener).onDown(eq(event)); 311 } 312 313 @Test testBroadcast()314 public void testBroadcast() { 315 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 316 final DreamTouchHandler touchHandler2 = Mockito.mock(DreamTouchHandler.class); 317 318 final Environment environment = new Environment(Stream.of(touchHandler, touchHandler2) 319 .collect(Collectors.toCollection(HashSet::new))); 320 321 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 322 environment.publishInputEvent(initialEvent); 323 324 final HashSet<InputChannelCompat.InputEventListener> inputListeners = new HashSet<>(); 325 326 inputListeners.add(registerInputEventListener(touchHandler)); 327 inputListeners.add(registerInputEventListener(touchHandler)); 328 inputListeners.add(registerInputEventListener(touchHandler2)); 329 330 final MotionEvent event = Mockito.mock(MotionEvent.class); 331 environment.publishInputEvent(event); 332 333 inputListeners 334 .stream() 335 .forEach(inputEventListener -> verify(inputEventListener).onInputEvent(event)); 336 } 337 338 @Test testPush()339 public void testPush() throws InterruptedException, ExecutionException { 340 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 341 342 final Environment environment = new Environment(Stream.of(touchHandler) 343 .collect(Collectors.toCollection(HashSet::new))); 344 345 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 346 environment.publishInputEvent(initialEvent); 347 348 final DreamTouchHandler.TouchSession session = captureSession(touchHandler); 349 final InputChannelCompat.InputEventListener eventListener = 350 registerInputEventListener(session); 351 352 final ListenableFuture<DreamTouchHandler.TouchSession> frontSessionFuture = session.push(); 353 environment.executeAll(); 354 final DreamTouchHandler.TouchSession frontSession = frontSessionFuture.get(); 355 final InputChannelCompat.InputEventListener frontEventListener = 356 registerInputEventListener(frontSession); 357 358 final MotionEvent event = Mockito.mock(MotionEvent.class); 359 environment.publishInputEvent(event); 360 361 verify(frontEventListener).onInputEvent(eq(event)); 362 verify(eventListener, never()).onInputEvent(any()); 363 364 Mockito.clearInvocations(eventListener, frontEventListener); 365 366 ListenableFuture<DreamTouchHandler.TouchSession> sessionFuture = frontSession.pop(); 367 environment.executeAll(); 368 369 DreamTouchHandler.TouchSession returnedSession = sessionFuture.get(); 370 assertThat(session == returnedSession).isTrue(); 371 372 environment.executeAll(); 373 374 final MotionEvent followupEvent = Mockito.mock(MotionEvent.class); 375 environment.publishInputEvent(followupEvent); 376 377 verify(eventListener).onInputEvent(eq(followupEvent)); 378 verify(frontEventListener, never()).onInputEvent(any()); 379 } 380 381 @Test testPop()382 public void testPop() { 383 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 384 final DreamTouchHandler.TouchSession.Callback callback = 385 Mockito.mock(DreamTouchHandler.TouchSession.Callback.class); 386 387 final Environment environment = new Environment(Stream.of(touchHandler) 388 .collect(Collectors.toCollection(HashSet::new))); 389 390 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 391 environment.publishInputEvent(initialEvent); 392 393 final DreamTouchHandler.TouchSession session = captureSession(touchHandler); 394 session.registerCallback(callback); 395 session.pop(); 396 environment.executeAll(); 397 398 verify(callback).onRemoved(); 399 } 400 401 @Test testPauseWithNoActiveSessions()402 public void testPauseWithNoActiveSessions() { 403 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 404 405 final Environment environment = new Environment(Stream.of(touchHandler) 406 .collect(Collectors.toCollection(HashSet::new))); 407 408 environment.updateLifecycle(observerOwnerPair -> { 409 observerOwnerPair.first.onPause(observerOwnerPair.second); 410 }); 411 412 environment.verifyInputSessionDispose(); 413 } 414 415 @Test testDeferredPauseWithActiveSessions()416 public void testDeferredPauseWithActiveSessions() { 417 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 418 419 final Environment environment = new Environment(Stream.of(touchHandler) 420 .collect(Collectors.toCollection(HashSet::new))); 421 422 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 423 environment.publishInputEvent(initialEvent); 424 425 // Ensure session started 426 final InputChannelCompat.InputEventListener eventListener = 427 registerInputEventListener(touchHandler); 428 429 // First event will be missed since we register after the execution loop, 430 final InputEvent event = Mockito.mock(InputEvent.class); 431 environment.publishInputEvent(event); 432 verify(eventListener).onInputEvent(eq(event)); 433 434 final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor = 435 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 436 437 verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture()); 438 439 environment.updateLifecycle(observerOwnerPair -> { 440 observerOwnerPair.first.onPause(observerOwnerPair.second); 441 }); 442 443 verify(environment.mInputSession, never()).dispose(); 444 445 // End session 446 touchSessionArgumentCaptor.getValue().pop(); 447 environment.executeAll(); 448 449 // Check to make sure the input session is now disposed. 450 environment.verifyInputSessionDispose(); 451 } 452 453 @Test testDestroyWithActiveSessions()454 public void testDestroyWithActiveSessions() { 455 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 456 457 final Environment environment = new Environment(Stream.of(touchHandler) 458 .collect(Collectors.toCollection(HashSet::new))); 459 460 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 461 environment.publishInputEvent(initialEvent); 462 463 // Ensure session started 464 final InputChannelCompat.InputEventListener eventListener = 465 registerInputEventListener(touchHandler); 466 467 // First event will be missed since we register after the execution loop, 468 final InputEvent event = Mockito.mock(InputEvent.class); 469 environment.publishInputEvent(event); 470 verify(eventListener).onInputEvent(eq(event)); 471 472 final ArgumentCaptor<DreamTouchHandler.TouchSession> touchSessionArgumentCaptor = 473 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 474 475 verify(touchHandler).onSessionStart(touchSessionArgumentCaptor.capture()); 476 477 environment.updateLifecycle(observerOwnerPair -> { 478 observerOwnerPair.first.onDestroy(observerOwnerPair.second); 479 }); 480 481 // Check to make sure the input session is now disposed. 482 environment.verifyInputSessionDispose(); 483 } 484 485 486 @Test testPilfering()487 public void testPilfering() { 488 final DreamTouchHandler touchHandler1 = Mockito.mock(DreamTouchHandler.class); 489 final DreamTouchHandler touchHandler2 = Mockito.mock(DreamTouchHandler.class); 490 491 final Environment environment = new Environment(Stream.of(touchHandler1, touchHandler2) 492 .collect(Collectors.toCollection(HashSet::new))); 493 494 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 495 environment.publishInputEvent(initialEvent); 496 497 final DreamTouchHandler.TouchSession session1 = captureSession(touchHandler1); 498 final GestureDetector.OnGestureListener gestureListener1 = 499 registerGestureListener(session1); 500 501 final DreamTouchHandler.TouchSession session2 = captureSession(touchHandler2); 502 final GestureDetector.OnGestureListener gestureListener2 = 503 registerGestureListener(session2); 504 when(gestureListener2.onDown(any())).thenReturn(true); 505 506 final MotionEvent gestureEvent = Mockito.mock(MotionEvent.class); 507 environment.publishGestureEvent( 508 onGestureListener -> onGestureListener.onDown(gestureEvent)); 509 510 Mockito.clearInvocations(gestureListener1, gestureListener2); 511 512 final MotionEvent followupEvent = Mockito.mock(MotionEvent.class); 513 environment.publishGestureEvent( 514 onGestureListener -> onGestureListener.onDown(followupEvent)); 515 516 verify(gestureListener1, never()).onDown(any()); 517 verify(gestureListener2).onDown(eq(followupEvent)); 518 } 519 520 @Test testOnRemovedCallbackOnStopMonitoring()521 public void testOnRemovedCallbackOnStopMonitoring() { 522 final DreamTouchHandler touchHandler = Mockito.mock(DreamTouchHandler.class); 523 final DreamTouchHandler.TouchSession.Callback callback = 524 Mockito.mock(DreamTouchHandler.TouchSession.Callback.class); 525 526 final Environment environment = new Environment(Stream.of(touchHandler) 527 .collect(Collectors.toCollection(HashSet::new))); 528 529 final InputEvent initialEvent = Mockito.mock(InputEvent.class); 530 environment.publishInputEvent(initialEvent); 531 532 final DreamTouchHandler.TouchSession session = captureSession(touchHandler); 533 session.registerCallback(callback); 534 535 environment.executeAll(); 536 537 environment.updateLifecycle(observerOwnerPair -> { 538 observerOwnerPair.first.onDestroy(observerOwnerPair.second); 539 }); 540 541 environment.executeAll(); 542 543 verify(callback).onRemoved(); 544 } 545 registerGestureListener(DreamTouchHandler handler)546 public GestureDetector.OnGestureListener registerGestureListener(DreamTouchHandler handler) { 547 final GestureDetector.OnGestureListener gestureListener = Mockito.mock( 548 GestureDetector.OnGestureListener.class); 549 final ArgumentCaptor<DreamTouchHandler.TouchSession> sessionCaptor = 550 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 551 verify(handler).onSessionStart(sessionCaptor.capture()); 552 sessionCaptor.getValue().registerGestureListener(gestureListener); 553 554 return gestureListener; 555 } 556 registerGestureListener( DreamTouchHandler.TouchSession session)557 public GestureDetector.OnGestureListener registerGestureListener( 558 DreamTouchHandler.TouchSession session) { 559 final GestureDetector.OnGestureListener gestureListener = Mockito.mock( 560 GestureDetector.OnGestureListener.class); 561 session.registerGestureListener(gestureListener); 562 563 return gestureListener; 564 } 565 registerInputEventListener( DreamTouchHandler.TouchSession session)566 public InputChannelCompat.InputEventListener registerInputEventListener( 567 DreamTouchHandler.TouchSession session) { 568 final InputChannelCompat.InputEventListener eventListener = Mockito.mock( 569 InputChannelCompat.InputEventListener.class); 570 session.registerInputListener(eventListener); 571 572 return eventListener; 573 } 574 captureSession(DreamTouchHandler handler)575 public DreamTouchHandler.TouchSession captureSession(DreamTouchHandler handler) { 576 final ArgumentCaptor<DreamTouchHandler.TouchSession> sessionCaptor = 577 ArgumentCaptor.forClass(DreamTouchHandler.TouchSession.class); 578 verify(handler).onSessionStart(sessionCaptor.capture()); 579 return sessionCaptor.getValue(); 580 } 581 registerInputEventListener( DreamTouchHandler handler)582 public InputChannelCompat.InputEventListener registerInputEventListener( 583 DreamTouchHandler handler) { 584 return registerInputEventListener(captureSession(handler)); 585 } 586 } 587