| /* |
| * Copyright 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.input.cts |
| |
| import android.accessibilityservice.AccessibilityServiceInfo |
| import android.app.Instrumentation |
| import android.view.accessibility.AccessibilityManager |
| import android.view.InputDevice |
| import android.view.KeyCharacterMap.VIRTUAL_KEYBOARD |
| import android.view.KeyEvent |
| import androidx.test.ext.junit.rules.ActivityScenarioRule |
| import androidx.test.ext.junit.runners.AndroidJUnit4 |
| import androidx.test.filters.MediumTest |
| import androidx.test.platform.app.InstrumentationRegistry |
| import com.android.compatibility.common.util.PollingCheck |
| import com.android.cts.input.UinputDevice |
| import org.junit.After |
| import org.junit.Assert.assertEquals |
| import org.junit.Assert.assertNotNull |
| import org.junit.Assert.assertNotEquals |
| import org.junit.Assert.assertTrue |
| import org.junit.Before |
| import org.junit.Rule |
| import org.junit.Test |
| import org.junit.runner.RunWith |
| |
| private fun setTouchExplorationEnabled(instrumentation: Instrumentation, enabled: Boolean) { |
| val TIMEOUT_FOR_SERVICE_ENABLE_MILLIS: Long = 10_000 // 10s |
| val manager: AccessibilityManager = |
| instrumentation.getTargetContext().getSystemService(AccessibilityManager::class.java) |
| |
| val uiAutomation = instrumentation.getUiAutomation() |
| val info = uiAutomation.getServiceInfo() |
| assertNotNull(info) |
| if (enabled) { |
| info.flags = info.flags or AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE |
| } else { |
| info.flags = (info.flags and |
| AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE.inv()) |
| } |
| uiAutomation.setServiceInfo(info) |
| |
| PollingCheck.waitFor(TIMEOUT_FOR_SERVICE_ENABLE_MILLIS) { |
| enabled == manager.isTouchExplorationEnabled() |
| } |
| } |
| |
| /** |
| * Create a virtual gamepad and enable accessibility services (any accessibility feature that would |
| * engage the inputfilter functionality inside InputDispatcher). |
| * Next, inject key events from the gamepad into the test activity and examine them. |
| */ |
| @MediumTest |
| @RunWith(AndroidJUnit4::class) |
| class GamepadWithAccessibilityTest { |
| @get:Rule |
| val activityRule = ActivityScenarioRule(CaptureEventActivity::class.java) |
| private lateinit var activity: CaptureEventActivity |
| private val instrumentation = InstrumentationRegistry.getInstrumentation() |
| |
| @Before |
| fun setUp() { |
| activityRule.getScenario().onActivity { |
| activity = it |
| } |
| PollingCheck.waitFor { activity.hasWindowFocus() } |
| setTouchExplorationEnabled(instrumentation, true) |
| } |
| |
| @After |
| fun tearDown() { |
| setTouchExplorationEnabled(instrumentation, false) |
| } |
| |
| /** |
| * The device id of input events received by the test activity should not be overwritten to -1. |
| * It should match the device id of the original input event. |
| */ |
| @Test |
| fun testDeviceId() { |
| val uinputDevice = UinputDevice.create(instrumentation, R.raw.google_gamepad_register, |
| InputDevice.SOURCE_KEYBOARD) |
| |
| val EV_SYN = 0 |
| val SYN_REPORT = 0 |
| val EV_KEY = 1 |
| val EV_KEY_DOWN = 1 |
| val EV_KEY_UP = 0 |
| val BTN_GAMEPAD = 0x130 |
| val evdevEventsDown = intArrayOf(EV_KEY, BTN_GAMEPAD, EV_KEY_DOWN, EV_SYN, SYN_REPORT, 0) |
| uinputDevice.injectEvents(evdevEventsDown.joinToString(prefix = "[", postfix = "]", |
| separator = ",")) |
| |
| val evdevEventsUp = intArrayOf(EV_KEY, BTN_GAMEPAD, EV_KEY_UP, EV_SYN, SYN_REPORT, 0) |
| uinputDevice.injectEvents(evdevEventsUp.joinToString(prefix = "[", postfix = "]", |
| separator = ",")) |
| |
| val lastInputEvent = activity.getInputEvent() |
| assertNotNull(lastInputEvent) |
| assertTrue(lastInputEvent is KeyEvent) |
| val keyEvent = lastInputEvent as KeyEvent |
| // The event was not modified by accessibility in any way, so it should not have |
| // KeyEvent.FLAG_IS_ACCESSIBILITY_EVENT in getFlags() |
| assertEquals(KeyEvent.FLAG_FROM_SYSTEM, keyEvent.getFlags()) |
| assertNotEquals(keyEvent.getDeviceId(), VIRTUAL_KEYBOARD) |
| assertEquals(keyEvent.getDeviceId(), uinputDevice.getDeviceId()) |
| } |
| } |