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