Add a virtual Dpad.
Bug: 244519097 Test: atest VirtualDpadTest and atest VirtualDeviceManagerServiceTest Change-Id: Iafce6fccee9f761e79e8fd845bb6e9b1e1490b26
This commit is contained in:
@@ -2803,6 +2803,7 @@ package android.companion.virtual {
|
||||
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
|
||||
method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
|
||||
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
|
||||
@@ -4372,6 +4373,11 @@ package android.hardware.hdmi {
|
||||
|
||||
package android.hardware.input {
|
||||
|
||||
public class VirtualDpad implements java.io.Closeable {
|
||||
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
|
||||
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
|
||||
}
|
||||
|
||||
public final class VirtualKeyEvent implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public int getAction();
|
||||
|
||||
@@ -57,6 +57,12 @@ interface IVirtualDevice {
|
||||
|
||||
void onAudioSessionEnded();
|
||||
|
||||
void createVirtualDpad(
|
||||
int displayId,
|
||||
String inputDeviceName,
|
||||
int vendorId,
|
||||
int productId,
|
||||
IBinder token);
|
||||
void createVirtualKeyboard(
|
||||
int displayId,
|
||||
String inputDeviceName,
|
||||
@@ -77,6 +83,7 @@ interface IVirtualDevice {
|
||||
IBinder token,
|
||||
in Point screenSize);
|
||||
void unregisterInputDevice(IBinder token);
|
||||
boolean sendDpadKeyEvent(IBinder token, in VirtualKeyEvent event);
|
||||
boolean sendKeyEvent(IBinder token, in VirtualKeyEvent event);
|
||||
boolean sendButtonEvent(IBinder token, in VirtualMouseButtonEvent event);
|
||||
boolean sendRelativeEvent(IBinder token, in VirtualMouseRelativeEvent event);
|
||||
|
||||
@@ -37,6 +37,7 @@ import android.hardware.display.DisplayManagerGlobal;
|
||||
import android.hardware.display.IVirtualDisplayCallback;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
import android.hardware.display.VirtualDisplayConfig;
|
||||
import android.hardware.input.VirtualDpad;
|
||||
import android.hardware.input.VirtualKeyboard;
|
||||
import android.hardware.input.VirtualMouse;
|
||||
import android.hardware.input.VirtualTouchscreen;
|
||||
@@ -314,6 +315,32 @@ public final class VirtualDeviceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a virtual dpad.
|
||||
*
|
||||
* @param display the display that the events inputted through this device should target
|
||||
* @param inputDeviceName the name to call this input device
|
||||
* @param vendorId the PCI vendor id
|
||||
* @param productId the product id, as defined by the vendor
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
@NonNull
|
||||
public VirtualDpad createVirtualDpad(
|
||||
@NonNull VirtualDisplay display,
|
||||
@NonNull String inputDeviceName,
|
||||
int vendorId,
|
||||
int productId) {
|
||||
try {
|
||||
final IBinder token = new Binder(
|
||||
"android.hardware.input.VirtualDpad:" + inputDeviceName);
|
||||
mVirtualDevice.createVirtualDpad(display.getDisplay().getDisplayId(),
|
||||
inputDeviceName, vendorId, productId, token);
|
||||
return new VirtualDpad(mVirtualDevice, token);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a virtual keyboard.
|
||||
*
|
||||
|
||||
94
core/java/android/hardware/input/VirtualDpad.java
Normal file
94
core/java/android/hardware/input/VirtualDpad.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.hardware.input;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SystemApi;
|
||||
import android.companion.virtual.IVirtualDevice;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A virtual dpad representing a key input mechanism on a remote device.
|
||||
*
|
||||
* This registers an InputDevice that is interpreted like a physically-connected device and
|
||||
* dispatches received events to it.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public class VirtualDpad implements Closeable {
|
||||
|
||||
private final Set<Integer> mSupportedKeyCodes =
|
||||
Collections.unmodifiableSet(
|
||||
new HashSet<>(
|
||||
Arrays.asList(
|
||||
KeyEvent.KEYCODE_DPAD_UP,
|
||||
KeyEvent.KEYCODE_DPAD_DOWN,
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT,
|
||||
KeyEvent.KEYCODE_DPAD_CENTER)));
|
||||
private final IVirtualDevice mVirtualDevice;
|
||||
private final IBinder mToken;
|
||||
|
||||
/** @hide */
|
||||
public VirtualDpad(IVirtualDevice virtualDevice, IBinder token) {
|
||||
mVirtualDevice = virtualDevice;
|
||||
mToken = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
public void close() {
|
||||
try {
|
||||
mVirtualDevice.unregisterInputDevice(mToken);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a key event to the system.
|
||||
*
|
||||
* Supported key codes are KEYCODE_DPAD_UP, KEYCODE_DPAD_DOWN, KEYCODE_DPAD_LEFT,
|
||||
* KEYCODE_DPAD_RIGHT and KEYCODE_DPAD_CENTER,
|
||||
*
|
||||
* @param event the event to send
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
public void sendKeyEvent(@NonNull VirtualKeyEvent event) {
|
||||
try {
|
||||
if (!mSupportedKeyCodes.contains(event.getKeyCode())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported key code "
|
||||
+ event.getKeyCode()
|
||||
+ " sent to a VirtualDpad input device.");
|
||||
}
|
||||
mVirtualDevice.sendDpadKeyEvent(mToken, event);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,6 +158,7 @@ public final class VirtualKeyEvent implements Parcelable {
|
||||
KeyEvent.KEYCODE_DPAD_UP,
|
||||
KeyEvent.KEYCODE_DPAD_LEFT,
|
||||
KeyEvent.KEYCODE_DPAD_RIGHT,
|
||||
KeyEvent.KEYCODE_DPAD_CENTER,
|
||||
KeyEvent.KEYCODE_MOVE_END,
|
||||
KeyEvent.KEYCODE_MOVE_HOME,
|
||||
KeyEvent.KEYCODE_PAGE_DOWN,
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.annotation.SystemApi;
|
||||
import android.companion.virtual.IVirtualDevice;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import java.io.Closeable;
|
||||
|
||||
@@ -37,6 +38,7 @@ import java.io.Closeable;
|
||||
@SystemApi
|
||||
public class VirtualKeyboard implements Closeable {
|
||||
|
||||
private final int mUnsupportedKeyCode = KeyEvent.KEYCODE_DPAD_CENTER;
|
||||
private final IVirtualDevice mVirtualDevice;
|
||||
private final IBinder mToken;
|
||||
|
||||
@@ -64,6 +66,11 @@ public class VirtualKeyboard implements Closeable {
|
||||
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
public void sendKeyEvent(@NonNull VirtualKeyEvent event) {
|
||||
try {
|
||||
if (mUnsupportedKeyCode == event.getKeyCode()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported key code " + event.getKeyCode()
|
||||
+ " sent to a VirtualKeyboard input device.");
|
||||
}
|
||||
mVirtualDevice.sendKeyEvent(mToken, event);
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
|
||||
@@ -61,10 +61,12 @@ class InputController {
|
||||
|
||||
private static final AtomicLong sNextPhysId = new AtomicLong(1);
|
||||
|
||||
static final String PHYS_TYPE_DPAD = "Dpad";
|
||||
static final String PHYS_TYPE_KEYBOARD = "Keyboard";
|
||||
static final String PHYS_TYPE_MOUSE = "Mouse";
|
||||
static final String PHYS_TYPE_TOUCHSCREEN = "Touchscreen";
|
||||
@StringDef(prefix = { "PHYS_TYPE_" }, value = {
|
||||
PHYS_TYPE_DPAD,
|
||||
PHYS_TYPE_KEYBOARD,
|
||||
PHYS_TYPE_MOUSE,
|
||||
PHYS_TYPE_TOUCHSCREEN,
|
||||
@@ -121,6 +123,22 @@ class InputController {
|
||||
}
|
||||
}
|
||||
|
||||
void createDpad(@NonNull String deviceName,
|
||||
int vendorId,
|
||||
int productId,
|
||||
@NonNull IBinder deviceToken,
|
||||
int displayId) {
|
||||
final String phys = createPhys(PHYS_TYPE_DPAD);
|
||||
try {
|
||||
createDeviceInternal(InputDeviceDescriptor.TYPE_DPAD, deviceName, vendorId,
|
||||
productId, deviceToken, displayId, phys,
|
||||
() -> mNativeWrapper.openUinputDpad(deviceName, vendorId, productId, phys));
|
||||
} catch (DeviceCreationException e) {
|
||||
throw new RuntimeException(
|
||||
"Failed to create virtual dpad device '" + deviceName + "'.", e);
|
||||
}
|
||||
}
|
||||
|
||||
void createKeyboard(@NonNull String deviceName,
|
||||
int vendorId,
|
||||
int productId,
|
||||
@@ -253,6 +271,19 @@ class InputController {
|
||||
InputManager.getInstance().addUniqueIdAssociation(phys, displayUniqueId);
|
||||
}
|
||||
|
||||
boolean sendDpadKeyEvent(@NonNull IBinder token, @NonNull VirtualKeyEvent event) {
|
||||
synchronized (mLock) {
|
||||
final InputDeviceDescriptor inputDeviceDescriptor = mInputDeviceDescriptors.get(
|
||||
token);
|
||||
if (inputDeviceDescriptor == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not send key event to input device for given token");
|
||||
}
|
||||
return mNativeWrapper.writeDpadKeyEvent(inputDeviceDescriptor.getFileDescriptor(),
|
||||
event.getKeyCode(), event.getAction());
|
||||
}
|
||||
}
|
||||
|
||||
boolean sendKeyEvent(@NonNull IBinder token, @NonNull VirtualKeyEvent event) {
|
||||
synchronized (mLock) {
|
||||
final InputDeviceDescriptor inputDeviceDescriptor = mInputDeviceDescriptors.get(
|
||||
@@ -366,6 +397,8 @@ class InputController {
|
||||
}
|
||||
}
|
||||
|
||||
private static native int nativeOpenUinputDpad(String deviceName, int vendorId,
|
||||
int productId, String phys);
|
||||
private static native int nativeOpenUinputKeyboard(String deviceName, int vendorId,
|
||||
int productId, String phys);
|
||||
private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId,
|
||||
@@ -373,6 +406,7 @@ class InputController {
|
||||
private static native int nativeOpenUinputTouchscreen(String deviceName, int vendorId,
|
||||
int productId, String phys, int height, int width);
|
||||
private static native boolean nativeCloseUinput(int fd);
|
||||
private static native boolean nativeWriteDpadKeyEvent(int fd, int androidKeyCode, int action);
|
||||
private static native boolean nativeWriteKeyEvent(int fd, int androidKeyCode, int action);
|
||||
private static native boolean nativeWriteButtonEvent(int fd, int buttonCode, int action);
|
||||
private static native boolean nativeWriteTouchEvent(int fd, int pointerId, int toolType,
|
||||
@@ -385,6 +419,10 @@ class InputController {
|
||||
/** Wrapper around the static native methods for tests. */
|
||||
@VisibleForTesting
|
||||
protected static class NativeWrapper {
|
||||
public int openUinputDpad(String deviceName, int vendorId, int productId, String phys) {
|
||||
return nativeOpenUinputDpad(deviceName, vendorId, productId, phys);
|
||||
}
|
||||
|
||||
public int openUinputKeyboard(String deviceName, int vendorId, int productId, String phys) {
|
||||
return nativeOpenUinputKeyboard(deviceName, vendorId, productId, phys);
|
||||
}
|
||||
@@ -403,6 +441,10 @@ class InputController {
|
||||
return nativeCloseUinput(fd);
|
||||
}
|
||||
|
||||
public boolean writeDpadKeyEvent(int fd, int androidKeyCode, int action) {
|
||||
return nativeWriteDpadKeyEvent(fd, androidKeyCode, action);
|
||||
}
|
||||
|
||||
public boolean writeKeyEvent(int fd, int androidKeyCode, int action) {
|
||||
return nativeWriteKeyEvent(fd, androidKeyCode, action);
|
||||
}
|
||||
@@ -433,10 +475,12 @@ class InputController {
|
||||
static final int TYPE_KEYBOARD = 1;
|
||||
static final int TYPE_MOUSE = 2;
|
||||
static final int TYPE_TOUCHSCREEN = 3;
|
||||
static final int TYPE_DPAD = 4;
|
||||
@IntDef(prefix = { "TYPE_" }, value = {
|
||||
TYPE_KEYBOARD,
|
||||
TYPE_MOUSE,
|
||||
TYPE_TOUCHSCREEN,
|
||||
TYPE_DPAD,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface Type {
|
||||
|
||||
@@ -344,6 +344,33 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
|
||||
@Override // Binder call
|
||||
public void createVirtualDpad(
|
||||
int displayId,
|
||||
@NonNull String deviceName,
|
||||
int vendorId,
|
||||
int productId,
|
||||
@NonNull IBinder deviceToken) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
|
||||
"Permission required to create a virtual dpad");
|
||||
synchronized (mVirtualDeviceLock) {
|
||||
if (!mVirtualDisplayIds.contains(displayId)) {
|
||||
throw new SecurityException(
|
||||
"Cannot create a virtual dpad for a display not associated with "
|
||||
+ "this virtual device");
|
||||
}
|
||||
}
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mInputController.createDpad(deviceName, vendorId, productId, deviceToken,
|
||||
displayId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public void createVirtualKeyboard(
|
||||
int displayId,
|
||||
@@ -436,6 +463,16 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public boolean sendDpadKeyEvent(IBinder token, VirtualKeyEvent event) {
|
||||
final long binderToken = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mInputController.sendDpadKeyEvent(token, event);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(binderToken);
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public boolean sendKeyEvent(IBinder token, VirtualKeyEvent event) {
|
||||
final long binderToken = Binder.clearCallingIdentity();
|
||||
|
||||
@@ -37,6 +37,7 @@ enum class DeviceType {
|
||||
KEYBOARD,
|
||||
MOUSE,
|
||||
TOUCHSCREEN,
|
||||
DPAD,
|
||||
};
|
||||
|
||||
enum class UinputAction {
|
||||
@@ -76,6 +77,13 @@ static std::map<int, int> TOOL_TYPE_MAPPING = {
|
||||
{AMOTION_EVENT_TOOL_TYPE_PALM, MT_TOOL_PALM},
|
||||
};
|
||||
|
||||
// Dpad keycode mapping from https://source.android.com/devices/input/keyboard-devices
|
||||
static std::map<int, int> DPAD_KEY_CODE_MAPPING = {
|
||||
{AKEYCODE_DPAD_DOWN, KEY_DOWN}, {AKEYCODE_DPAD_UP, KEY_UP},
|
||||
{AKEYCODE_DPAD_LEFT, KEY_LEFT}, {AKEYCODE_DPAD_RIGHT, KEY_RIGHT},
|
||||
{AKEYCODE_DPAD_CENTER, KEY_SELECT},
|
||||
};
|
||||
|
||||
// Keycode mapping from https://source.android.com/devices/input/keyboard-devices
|
||||
static std::map<int, int> KEY_CODE_MAPPING = {
|
||||
{AKEYCODE_0, KEY_0},
|
||||
@@ -200,8 +208,13 @@ static int openUinput(const char* readableName, jint vendorId, jint productId, c
|
||||
ioctl(fd, UI_SET_EVBIT, EV_KEY);
|
||||
ioctl(fd, UI_SET_EVBIT, EV_SYN);
|
||||
switch (deviceType) {
|
||||
case DeviceType::DPAD:
|
||||
for (const auto& [_, keyCode] : DPAD_KEY_CODE_MAPPING) {
|
||||
ioctl(fd, UI_SET_KEYBIT, keyCode);
|
||||
}
|
||||
break;
|
||||
case DeviceType::KEYBOARD:
|
||||
for (const auto& [ignored, keyCode] : KEY_CODE_MAPPING) {
|
||||
for (const auto& [_, keyCode] : KEY_CODE_MAPPING) {
|
||||
ioctl(fd, UI_SET_KEYBIT, keyCode);
|
||||
}
|
||||
break;
|
||||
@@ -327,6 +340,12 @@ static int openUinputJni(JNIEnv* env, jstring name, jint vendorId, jint productI
|
||||
screenHeight, screenWidth);
|
||||
}
|
||||
|
||||
static int nativeOpenUinputDpad(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
return openUinputJni(env, name, vendorId, productId, phys, DeviceType::DPAD,
|
||||
/* screenHeight */ 0, /* screenWidth */ 0);
|
||||
}
|
||||
|
||||
static int nativeOpenUinputKeyboard(JNIEnv* env, jobject thiz, jstring name, jint vendorId,
|
||||
jint productId, jstring phys) {
|
||||
return openUinputJni(env, name, vendorId, productId, phys, DeviceType::KEYBOARD,
|
||||
@@ -355,10 +374,10 @@ static bool writeInputEvent(int fd, uint16_t type, uint16_t code, int32_t value)
|
||||
return TEMP_FAILURE_RETRY(write(fd, &ev, sizeof(struct input_event))) == sizeof(ev);
|
||||
}
|
||||
|
||||
static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint androidKeyCode,
|
||||
jint action) {
|
||||
auto keyCodeIterator = KEY_CODE_MAPPING.find(androidKeyCode);
|
||||
if (keyCodeIterator == KEY_CODE_MAPPING.end()) {
|
||||
static bool writeKeyEvent(jint fd, jint androidKeyCode, jint action,
|
||||
const std::map<int, int>& keyCodeMapping) {
|
||||
auto keyCodeIterator = keyCodeMapping.find(androidKeyCode);
|
||||
if (keyCodeIterator == keyCodeMapping.end()) {
|
||||
ALOGE("No supportive native keycode for androidKeyCode %d", androidKeyCode);
|
||||
return false;
|
||||
}
|
||||
@@ -376,6 +395,16 @@ static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint android
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool nativeWriteDpadKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint androidKeyCode,
|
||||
jint action) {
|
||||
return writeKeyEvent(fd, androidKeyCode, action, DPAD_KEY_CODE_MAPPING);
|
||||
}
|
||||
|
||||
static bool nativeWriteKeyEvent(JNIEnv* env, jobject thiz, jint fd, jint androidKeyCode,
|
||||
jint action) {
|
||||
return writeKeyEvent(fd, androidKeyCode, action, KEY_CODE_MAPPING);
|
||||
}
|
||||
|
||||
static bool nativeWriteButtonEvent(JNIEnv* env, jobject thiz, jint fd, jint buttonCode,
|
||||
jint action) {
|
||||
auto buttonCodeIterator = BUTTON_CODE_MAPPING.find(buttonCode);
|
||||
@@ -461,6 +490,8 @@ static bool nativeWriteScrollEvent(JNIEnv* env, jobject thiz, jint fd, jfloat xA
|
||||
}
|
||||
|
||||
static JNINativeMethod methods[] = {
|
||||
{"nativeOpenUinputDpad", "(Ljava/lang/String;IILjava/lang/String;)I",
|
||||
(void*)nativeOpenUinputDpad},
|
||||
{"nativeOpenUinputKeyboard", "(Ljava/lang/String;IILjava/lang/String;)I",
|
||||
(void*)nativeOpenUinputKeyboard},
|
||||
{"nativeOpenUinputMouse", "(Ljava/lang/String;IILjava/lang/String;)I",
|
||||
@@ -468,6 +499,7 @@ static JNINativeMethod methods[] = {
|
||||
{"nativeOpenUinputTouchscreen", "(Ljava/lang/String;IILjava/lang/String;II)I",
|
||||
(void*)nativeOpenUinputTouchscreen},
|
||||
{"nativeCloseUinput", "(I)Z", (void*)nativeCloseUinput},
|
||||
{"nativeWriteDpadKeyEvent", "(III)Z", (void*)nativeWriteDpadKeyEvent},
|
||||
{"nativeWriteKeyEvent", "(III)Z", (void*)nativeWriteKeyEvent},
|
||||
{"nativeWriteButtonEvent", "(III)Z", (void*)nativeWriteButtonEvent},
|
||||
{"nativeWriteTouchEvent", "(IIIIFFFF)Z", (void*)nativeWriteTouchEvent},
|
||||
|
||||
@@ -57,6 +57,8 @@ class InputManagerMockHelper {
|
||||
|
||||
doAnswer(this::handleNativeOpenInputDevice).when(mNativeWrapperMock).openUinputMouse(
|
||||
anyString(), anyInt(), anyInt(), anyString());
|
||||
doAnswer(this::handleNativeOpenInputDevice).when(mNativeWrapperMock).openUinputDpad(
|
||||
anyString(), anyInt(), anyInt(), anyString());
|
||||
doAnswer(this::handleNativeOpenInputDevice).when(mNativeWrapperMock).openUinputKeyboard(
|
||||
anyString(), anyInt(), anyInt(), anyString());
|
||||
doAnswer(this::handleNativeOpenInputDevice).when(mNativeWrapperMock).openUinputTouchscreen(
|
||||
|
||||
@@ -386,6 +386,14 @@ public class VirtualDeviceManagerServiceTest {
|
||||
verify(mIPowerManagerMock).releaseWakeLock(eq(wakeLock), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVirtualDpad_noDisplay_failsSecurityException() {
|
||||
assertThrows(
|
||||
SecurityException.class,
|
||||
() -> mDeviceImpl.createVirtualDpad(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
|
||||
PRODUCT_ID, BINDER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVirtualKeyboard_noDisplay_failsSecurityException() {
|
||||
assertThrows(
|
||||
@@ -417,6 +425,17 @@ public class VirtualDeviceManagerServiceTest {
|
||||
DISPLAY_ID, mRoutingCallback, mConfigChangedCallback));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVirtualDpad_noPermission_failsSecurityException() {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
|
||||
doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
|
||||
eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
|
||||
assertThrows(
|
||||
SecurityException.class,
|
||||
() -> mDeviceImpl.createVirtualDpad(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
|
||||
PRODUCT_ID, BINDER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVirtualKeyboard_noPermission_failsSecurityException() {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
|
||||
@@ -467,6 +486,17 @@ public class VirtualDeviceManagerServiceTest {
|
||||
assertThrows(SecurityException.class, () -> mDeviceImpl.onAudioSessionEnded());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVirtualDpad_hasDisplay_obtainFileDescriptor() {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
|
||||
mDeviceImpl.createVirtualDpad(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
|
||||
BINDER);
|
||||
assertWithMessage("Virtual dpad should register fd when the display matches")
|
||||
.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
|
||||
verify(mNativeWrapperMock).openUinputDpad(eq(DEVICE_NAME), eq(VENDOR_ID),
|
||||
eq(PRODUCT_ID), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
|
||||
@@ -483,7 +513,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
|
||||
mDeviceImpl.createVirtualMouse(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
|
||||
BINDER);
|
||||
assertWithMessage("Virtual keyboard should register fd when the display matches")
|
||||
assertWithMessage("Virtual mouse should register fd when the display matches")
|
||||
.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
|
||||
verify(mNativeWrapperMock).openUinputMouse(eq(DEVICE_NAME), eq(VENDOR_ID), eq(PRODUCT_ID),
|
||||
anyString());
|
||||
@@ -494,7 +524,7 @@ public class VirtualDeviceManagerServiceTest {
|
||||
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
|
||||
mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
|
||||
BINDER, new Point(WIDTH, HEIGHT));
|
||||
assertWithMessage("Virtual keyboard should register fd when the display matches")
|
||||
assertWithMessage("Virtual touchscreen should register fd when the display matches")
|
||||
.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
|
||||
verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME), eq(VENDOR_ID),
|
||||
eq(PRODUCT_ID), anyString(), eq(HEIGHT), eq(WIDTH));
|
||||
|
||||
Reference in New Issue
Block a user