1 /* <lambda>null2 * Copyright 2024 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 android.input.cts 18 19 import android.app.Activity 20 import android.graphics.Color 21 import android.server.wm.CtsWindowInfoUtils.waitForWindowVisible 22 import android.view.Gravity 23 import android.view.InputDevice.SOURCE_STYLUS 24 import android.view.InputDevice.SOURCE_TOUCHSCREEN 25 import android.view.InputEvent 26 import android.view.KeyEvent 27 import android.view.MotionEvent 28 import android.view.View 29 import android.view.ViewGroup 30 import android.view.WindowInsets 31 import android.view.WindowManager 32 import android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL 33 import android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH 34 import android.view.WindowManager.LayoutParams.TYPE_APPLICATION 35 import java.util.concurrent.FutureTask 36 import java.util.concurrent.LinkedBlockingQueue 37 import java.util.concurrent.TimeUnit 38 import org.junit.Assert.assertNull 39 import org.junit.Assert.fail 40 41 private fun assertNoEvents(queue: LinkedBlockingQueue<InputEvent>) { 42 val event = queue.poll(100, TimeUnit.MILLISECONDS) 43 assertNull("Expected no events, but received $event", event) 44 } 45 46 class TwoWindowsActivity : Activity() { 47 private val leftWindowEvents = LinkedBlockingQueue<InputEvent>() 48 private val rightWindowEvents = LinkedBlockingQueue<InputEvent>() 49 50 /** 51 * Launch two windows and wait for them to be visible. Must not be called on UI thread. 52 */ launchTwoWindowsnull53 fun launchTwoWindows() { 54 lateinit var leftView: View 55 lateinit var rightView: View 56 val addWindowsTask = FutureTask<Unit> { 57 val wm = getSystemService(WindowManager::class.java) 58 var wmlp = WindowManager.LayoutParams( 59 TYPE_APPLICATION, 60 FLAG_NOT_TOUCH_MODAL or FLAG_SPLIT_TOUCH 61 ) 62 63 val windowMetrics = windowManager.currentWindowMetrics 64 val insets = windowMetrics.windowInsets.getInsetsIgnoringVisibility( 65 WindowInsets.Type.systemBars() 66 ) 67 val width = windowMetrics.bounds.width() - insets.left - insets.right 68 val height = windowMetrics.bounds.height() - insets.top - insets.bottom 69 70 wmlp.setTitle("Left -- " + getPackageName()) 71 wmlp.width = width / 2 72 wmlp.height = height 73 wmlp.gravity = Gravity.TOP or Gravity.LEFT 74 wmlp.setTitle(getPackageName()) 75 76 val vglp = ViewGroup.LayoutParams( 77 ViewGroup.LayoutParams.MATCH_PARENT, 78 ViewGroup.LayoutParams.MATCH_PARENT 79 ) 80 81 leftView = View(this) 82 leftView.setOnTouchListener { _: View, event: MotionEvent -> 83 leftWindowEvents.add(MotionEvent.obtain(event)); true } 84 leftView.setOnHoverListener { _, event -> 85 leftWindowEvents.add(MotionEvent.obtain(event)); true } 86 leftView.setBackgroundColor(Color.GREEN) 87 leftView.setLayoutParams(vglp) 88 wm.addView(leftView, wmlp) 89 90 wmlp.setTitle("Right -- " + getPackageName()) 91 wmlp.gravity = Gravity.TOP or Gravity.RIGHT 92 93 rightView = View(this) 94 rightView.setBackgroundColor(Color.BLUE) 95 rightView.setOnTouchListener{ _: View, event: MotionEvent -> 96 rightWindowEvents.add(MotionEvent.obtain(event)); true } 97 rightView.setOnHoverListener { _, event -> 98 rightWindowEvents.add(MotionEvent.obtain(event)); true } 99 rightView.setLayoutParams(vglp) 100 101 wm.addView(rightView, wmlp) 102 103 // Disable resampling, otherwise ACTION_MOVE events could contain unexpected coordinates 104 leftView.requestUnbufferedDispatch(SOURCE_TOUCHSCREEN or SOURCE_STYLUS) 105 rightView.requestUnbufferedDispatch(SOURCE_TOUCHSCREEN or SOURCE_STYLUS) 106 } 107 runOnUiThread(addWindowsTask) 108 try { 109 addWindowsTask.get(); // this will block until FutureTask completes on the main thread 110 } catch (e: Exception) { 111 fail("Interrupted while waiting to add windows") 112 } 113 114 waitForWindowVisible(leftView) 115 waitForWindowVisible(rightView) 116 } 117 dispatchGenericMotionEventnull118 override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean { 119 fail("Unexpected event " + ev) 120 return true 121 } 122 dispatchTouchEventnull123 override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { 124 fail("Unexpected event " + ev) 125 return true 126 } 127 dispatchKeyEventnull128 override fun dispatchKeyEvent(ev: KeyEvent?): Boolean { 129 fail("Unexpected event " + ev) 130 return true 131 } 132 dispatchTrackballEventnull133 override fun dispatchTrackballEvent(ev: MotionEvent?): Boolean { 134 fail("Unexpected event " + ev) 135 return true 136 } 137 getLeftWindowInputEventnull138 fun getLeftWindowInputEvent(): InputEvent? { 139 return leftWindowEvents.poll(5, TimeUnit.SECONDS) 140 } 141 getRightWindowInputEventnull142 fun getRightWindowInputEvent(): InputEvent? { 143 return rightWindowEvents.poll(5, TimeUnit.SECONDS) 144 } 145 assertNoEventsnull146 fun assertNoEvents() { 147 assertNoEvents(leftWindowEvents) 148 assertNoEvents(rightWindowEvents) 149 } 150 } 151