1 /* <lambda>null2 * Copyright (C) 2021 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.test.input 18 19 import android.os.HandlerThread 20 import android.view.InputChannel 21 import android.view.InputDevice 22 import android.view.MotionEvent 23 import android.view.WindowManagerPolicyConstants.PointerEventListener 24 import com.android.server.UiThread 25 import com.android.server.wm.PointerEventDispatcher 26 import org.junit.After 27 import org.junit.Assert.assertEquals 28 import org.junit.Before 29 import org.junit.Test 30 31 private class CrashingPointerEventListener : PointerEventListener { 32 override fun onPointerEvent(motionEvent: MotionEvent) { 33 throw IllegalArgumentException("This listener crashes when input event occurs") 34 } 35 } 36 37 class PointerEventDispatcherTest { 38 companion object { 39 private const val TAG = "PointerEventDispatcherTest" 40 } 41 42 private val mHandlerThread = HandlerThread("Process input events") 43 private lateinit var mSender: SpyInputEventSender 44 private lateinit var mPointerEventDispatcher: PointerEventDispatcher 45 private val mListener = CrashingPointerEventListener() 46 47 @Before setUpnull48 fun setUp() { 49 val channels = InputChannel.openInputChannelPair("TestChannel") 50 51 mHandlerThread.start() 52 val looper = mHandlerThread.getLooper() 53 mSender = SpyInputEventSender(channels[0], looper) 54 55 mPointerEventDispatcher = PointerEventDispatcher(channels[1]) 56 mPointerEventDispatcher.registerInputEventListener(mListener) 57 } 58 59 @After tearDownnull60 fun tearDown() { 61 mHandlerThread.quitSafely() 62 } 63 64 @Test testSendMotionToCrashingListenerDoesNotCrashnull65 fun testSendMotionToCrashingListenerDoesNotCrash() { 66 // The exception will occur on the UiThread, so we can't catch it here on the test thread 67 UiThread.get().setUncaughtExceptionHandler { thread, exception -> 68 if (thread == UiThread.get() && exception is IllegalArgumentException) { 69 // do nothing - this is the exception that we need to ignore 70 } else { 71 throw exception 72 } 73 } 74 75 // The MotionEvent properties aren't important for this test, as long as the event 76 // is a pointer event, so that it gets processed by CrashingPointerEventListener 77 val downTime = 0L 78 val motionEvent = 79 MotionEvent.obtain( 80 downTime, 81 downTime, 82 MotionEvent.ACTION_DOWN, 83 0f /* x */, 84 0f /* y */, 85 0, /* metaState */ 86 ) 87 motionEvent.source = InputDevice.SOURCE_TOUCHSCREEN 88 val seq = 10 89 mSender.sendInputEvent(seq, motionEvent) 90 val finishedSignal = mSender.getFinishedSignal() 91 92 // Since the listener raises an exception during the event handling, the event should be 93 // marked as 'not handled'. 94 assertEquals(SpyInputEventSender.FinishedSignal(seq, handled = false), finishedSignal) 95 // Ensure that there aren't double finish calls. 96 mSender.assertNoEvents() 97 } 98 } 99