Use VirtualInputDeviceConfig subclasses to create virtual input devices.

These config classes encapsulates the config parameters. This is to keep
the argument list of createVirtualFoo APIs from growing longer every
time we add new config parameters to an input device. Only shared common
configurations such as product ID are held in VirtualInputDeviceConfig.
Optional parameters such the sizes for touchscreen will be held by the
corresponding subtypes dedicated for that input device. This way we keep
what is settable for each device clear.

Bug: 237537306
Test: atest CtsVirtualDevicesTestCases CtsHardwareTestCases

Change-Id: I609d109891fe871367869c730ed1905be8889f89
This commit is contained in:
Zixuan Qu
2022-11-24 06:57:16 +00:00
parent 4dbae54d6e
commit 290b4fd61a
15 changed files with 928 additions and 206 deletions

View File

@@ -2959,10 +2959,13 @@ package android.companion.virtual {
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 @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull java.util.List<java.lang.String>, @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);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.input.VirtualDpadConfig);
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.input.VirtualKeyboardConfig);
method @Deprecated @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.input.VirtualMouseConfig);
method @Deprecated @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.input.VirtualTouchscreenConfig);
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
method public int getDeviceId();
method @Nullable public android.companion.virtual.sensor.VirtualSensor getVirtualSensor(int, @NonNull String);
method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
@@ -4609,6 +4612,34 @@ package android.hardware.input {
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
}
public final class VirtualDpadConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualDpadConfig> CREATOR;
}
public static final class VirtualDpadConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualDpadConfig.Builder> {
ctor public VirtualDpadConfig.Builder();
method @NonNull public android.hardware.input.VirtualDpadConfig build();
}
public abstract class VirtualInputDeviceConfig {
ctor protected VirtualInputDeviceConfig(@NonNull android.hardware.input.VirtualInputDeviceConfig.Builder<? extends android.hardware.input.VirtualInputDeviceConfig.Builder<?>>);
ctor protected VirtualInputDeviceConfig(@NonNull android.os.Parcel);
method public int getAssociatedDisplayId();
method @NonNull public String getInputDeviceName();
method public int getProductId();
method public int getVendorId();
}
public abstract static class VirtualInputDeviceConfig.Builder<T extends android.hardware.input.VirtualInputDeviceConfig.Builder<T>> {
ctor public VirtualInputDeviceConfig.Builder();
method @NonNull public T setAssociatedDisplayId(int);
method @NonNull public T setInputDeviceName(@NonNull String);
method @NonNull public T setProductId(int);
method @NonNull public T setVendorId(int);
}
public final class VirtualKeyEvent implements android.os.Parcelable {
method public int describeContents();
method public int getAction();
@@ -4631,6 +4662,17 @@ package android.hardware.input {
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
}
public final class VirtualKeyboardConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualKeyboardConfig> CREATOR;
}
public static final class VirtualKeyboardConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualKeyboardConfig.Builder> {
ctor public VirtualKeyboardConfig.Builder();
method @NonNull public android.hardware.input.VirtualKeyboardConfig build();
}
public class VirtualMouse implements java.io.Closeable {
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.graphics.PointF getCursorPosition();
@@ -4661,6 +4703,17 @@ package android.hardware.input {
method @NonNull public android.hardware.input.VirtualMouseButtonEvent.Builder setButtonCode(int);
}
public final class VirtualMouseConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualMouseConfig> CREATOR;
}
public static final class VirtualMouseConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualMouseConfig.Builder> {
ctor public VirtualMouseConfig.Builder();
method @NonNull public android.hardware.input.VirtualMouseConfig build();
}
public final class VirtualMouseRelativeEvent implements android.os.Parcelable {
method public int describeContents();
method public float getRelativeX();
@@ -4727,6 +4780,21 @@ package android.hardware.input {
method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendTouchEvent(@NonNull android.hardware.input.VirtualTouchEvent);
}
public final class VirtualTouchscreenConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
method public int describeContents();
method public int getHeightInPixels();
method public int getWidthInPixels();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualTouchscreenConfig> CREATOR;
}
public static final class VirtualTouchscreenConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualTouchscreenConfig.Builder> {
ctor public VirtualTouchscreenConfig.Builder();
method @NonNull public android.hardware.input.VirtualTouchscreenConfig build();
method @NonNull public android.hardware.input.VirtualTouchscreenConfig.Builder setHeightInPixels(int);
method @NonNull public android.hardware.input.VirtualTouchscreenConfig.Builder setWidthInPixels(int);
}
}
package android.hardware.lights {

View File

@@ -24,11 +24,15 @@ import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.input.VirtualDpadConfig;
import android.hardware.input.VirtualKeyboardConfig;
import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualMouseButtonEvent;
import android.hardware.input.VirtualMouseConfig;
import android.hardware.input.VirtualMouseRelativeEvent;
import android.hardware.input.VirtualMouseScrollEvent;
import android.hardware.input.VirtualTouchEvent;
import android.hardware.input.VirtualTouchscreenConfig;
import android.os.ResultReceiver;
/**
@@ -64,32 +68,22 @@ interface IVirtualDevice {
IAudioConfigChangedCallback configChangedCallback);
void onAudioSessionEnded();
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
void createVirtualDpad(
int displayId,
String inputDeviceName,
int vendorId,
int productId,
in VirtualDpadConfig config,
IBinder token);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
void createVirtualKeyboard(
int displayId,
String inputDeviceName,
int vendorId,
int productId,
in VirtualKeyboardConfig config,
IBinder token);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
void createVirtualMouse(
int displayId,
String inputDeviceName,
int vendorId,
int productId,
in VirtualMouseConfig config,
IBinder token);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
void createVirtualTouchscreen(
int displayId,
String inputDeviceName,
int vendorId,
int productId,
IBinder token,
in Point screenSize);
in VirtualTouchscreenConfig config,
IBinder token);
void unregisterInputDevice(IBinder token);
int getInputDeviceId(IBinder token);
boolean sendDpadKeyEvent(IBinder token, in VirtualKeyEvent event);

View File

@@ -41,9 +41,13 @@ import android.hardware.display.IVirtualDisplayCallback;
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.hardware.input.VirtualDpad;
import android.hardware.input.VirtualDpadConfig;
import android.hardware.input.VirtualKeyboard;
import android.hardware.input.VirtualKeyboardConfig;
import android.hardware.input.VirtualMouse;
import android.hardware.input.VirtualMouseConfig;
import android.hardware.input.VirtualTouchscreen;
import android.hardware.input.VirtualTouchscreenConfig;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -500,23 +504,15 @@ 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
* @param config the configurations of the virtual Dpad.
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualDpad createVirtualDpad(
@NonNull VirtualDisplay display,
@NonNull String inputDeviceName,
int vendorId,
int productId) {
public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
try {
final IBinder token = new Binder(
"android.hardware.input.VirtualDpad:" + inputDeviceName);
mVirtualDevice.createVirtualDpad(display.getDisplay().getDisplayId(),
inputDeviceName, vendorId, productId, token);
"android.hardware.input.VirtualDpad:" + config.getInputDeviceName());
mVirtualDevice.createVirtualDpad(config, token);
return new VirtualDpad(mVirtualDevice, token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -526,50 +522,106 @@ public final class VirtualDeviceManager {
/**
* Creates a virtual keyboard.
*
* @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
* @param config the configurations of the virtual keyboard.
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualKeyboard createVirtualKeyboard(
@NonNull VirtualDisplay display,
@NonNull String inputDeviceName,
int vendorId,
int productId) {
public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) {
try {
final IBinder token = new Binder(
"android.hardware.input.VirtualKeyboard:" + inputDeviceName);
mVirtualDevice.createVirtualKeyboard(display.getDisplay().getDisplayId(),
inputDeviceName, vendorId, productId, token);
"android.hardware.input.VirtualKeyboard:" + config.getInputDeviceName());
mVirtualDevice.createVirtualKeyboard(config, token);
return new VirtualKeyboard(mVirtualDevice, token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Creates a virtual keyboard.
*
* @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
* @see #createVirtualKeyboard(VirtualKeyboardConfig config)
* @deprecated Use {@link #createVirtualKeyboard(VirtualKeyboardConfig config)} instead
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualDisplay display,
@NonNull String inputDeviceName, int vendorId, int productId) {
VirtualKeyboardConfig keyboardConfig =
new VirtualKeyboardConfig.Builder()
.setVendorId(vendorId)
.setProductId(productId)
.setInputDeviceName(inputDeviceName)
.setAssociatedDisplayId(display.getDisplay().getDisplayId())
.build();
return createVirtualKeyboard(keyboardConfig);
}
/**
* Creates a virtual mouse.
*
* @param config the configurations of the virtual mouse.
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) {
try {
final IBinder token = new Binder(
"android.hardware.input.VirtualMouse:" + config.getInputDeviceName());
mVirtualDevice.createVirtualMouse(config, token);
return new VirtualMouse(mVirtualDevice, token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Creates a virtual mouse.
*
* @param display the display that the events inputted through this device should target
* @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
* @param vendorId the PCI vendor id
* @param productId the product id, as defined by the vendor
* @see #createVirtualMouse(VirtualMouseConfig config)
* @deprecated Use {@link #createVirtualMouse(VirtualMouseConfig config)} instead
* *
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualMouse createVirtualMouse(@NonNull VirtualDisplay display,
@NonNull String inputDeviceName, int vendorId, int productId) {
VirtualMouseConfig mouseConfig =
new VirtualMouseConfig.Builder()
.setVendorId(vendorId)
.setProductId(productId)
.setInputDeviceName(inputDeviceName)
.setAssociatedDisplayId(display.getDisplay().getDisplayId())
.build();
return createVirtualMouse(mouseConfig);
}
/**
* Creates a virtual touchscreen.
*
* @param config the configurations of the virtual touchscreen.
*/
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualMouse createVirtualMouse(
@NonNull VirtualDisplay display,
@NonNull String inputDeviceName,
int vendorId,
int productId) {
public VirtualTouchscreen createVirtualTouchscreen(
@NonNull VirtualTouchscreenConfig config) {
try {
final IBinder token = new Binder(
"android.hardware.input.VirtualMouse:" + inputDeviceName);
mVirtualDevice.createVirtualMouse(display.getDisplay().getDisplayId(),
inputDeviceName, vendorId, productId, token);
return new VirtualMouse(mVirtualDevice, token);
"android.hardware.input.VirtualTouchscreen:" + config.getInputDeviceName());
mVirtualDevice.createVirtualTouchscreen(config, token);
return new VirtualTouchscreen(mVirtualDevice, token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -578,29 +630,32 @@ public final class VirtualDeviceManager {
/**
* Creates a virtual touchscreen.
*
* @param display the display that the events inputted through this device should target
* @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
* @param vendorId the PCI vendor id
* @param productId the product id, as defined by the vendor
* @see #createVirtualTouchscreen(VirtualTouchscreenConfig config)
* @deprecated Use {@link #createVirtualTouchscreen(VirtualTouchscreenConfig config)}
* instead
*/
@Deprecated
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@NonNull
public VirtualTouchscreen createVirtualTouchscreen(
@NonNull VirtualDisplay display,
@NonNull String inputDeviceName,
int vendorId,
int productId) {
try {
final IBinder token = new Binder(
"android.hardware.input.VirtualTouchscreen:" + inputDeviceName);
final Point size = new Point();
display.getDisplay().getSize(size);
mVirtualDevice.createVirtualTouchscreen(display.getDisplay().getDisplayId(),
inputDeviceName, vendorId, productId, token, size);
return new VirtualTouchscreen(mVirtualDevice, token);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
public VirtualTouchscreen createVirtualTouchscreen(@NonNull VirtualDisplay display,
@NonNull String inputDeviceName, int vendorId, int productId) {
final Point size = new Point();
display.getDisplay().getSize(size);
VirtualTouchscreenConfig touchscreenConfig =
new VirtualTouchscreenConfig.Builder()
.setVendorId(vendorId)
.setProductId(productId)
.setInputDeviceName(inputDeviceName)
.setAssociatedDisplayId(display.getDisplay().getDisplayId())
.setWidthInPixels(size.x)
.setHeightInPixels(size.y)
.build();
return createVirtualTouchscreen(touchscreenConfig);
}
/**

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable VirtualDpadConfig;

View File

@@ -0,0 +1,75 @@
/*
* 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.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Configurations to create virtual Dpad.
*
* @hide
*/
@SystemApi
public final class VirtualDpadConfig extends VirtualInputDeviceConfig implements Parcelable {
@NonNull
public static final Creator<VirtualDpadConfig> CREATOR = new Creator<VirtualDpadConfig>() {
@Override
public VirtualDpadConfig createFromParcel(Parcel in) {
return new VirtualDpadConfig(in);
}
@Override
public VirtualDpadConfig[] newArray(int size) {
return new VirtualDpadConfig[size];
}
};
private VirtualDpadConfig(@NonNull VirtualDpadConfig.Builder builder) {
super(builder);
}
private VirtualDpadConfig(@NonNull Parcel in) {
super(in);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
}
/**
* Builder for creating a {@link VirtualDpadConfig}.
*/
public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
/**
* Builds the {@link VirtualDpadConfig} instance.
*/
@NonNull
public VirtualDpadConfig build() {
return new VirtualDpadConfig(this);
}
}
}

View File

@@ -0,0 +1,144 @@
/*
* 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.SystemApi;
import android.os.Parcel;
/**
* Common configurations to create virtual input devices.
*
* @hide
*/
@SystemApi
public abstract class VirtualInputDeviceConfig {
/** The vendor id uniquely identifies the company who manufactured the device. */
private final int mVendorId;
/**
* The product id uniquely identifies which product within the address space of a given vendor,
* identified by the device's vendor id.
*/
private final int mProductId;
/** The associated display ID of the virtual input device. */
private final int mAssociatedDisplayId;
/** The name of the virtual input device. */
@NonNull
private final String mInputDeviceName;
protected VirtualInputDeviceConfig(@NonNull Builder<? extends Builder<?>> builder) {
mVendorId = builder.mVendorId;
mProductId = builder.mProductId;
mAssociatedDisplayId = builder.mAssociatedDisplayId;
mInputDeviceName = builder.mInputDeviceName;
}
protected VirtualInputDeviceConfig(@NonNull Parcel in) {
mVendorId = in.readInt();
mProductId = in.readInt();
mAssociatedDisplayId = in.readInt();
mInputDeviceName = in.readString8();
}
/**
* The vendor id uniquely identifies the company who manufactured the device.
*/
public int getVendorId() {
return mVendorId;
}
/**
* The product id uniquely identifies which product within the address space of a given vendor,
* identified by the device's vendor id.
*/
public int getProductId() {
return mProductId;
}
/**
* The associated display ID of the virtual input device.
*/
public int getAssociatedDisplayId() {
return mAssociatedDisplayId;
}
/**
* The name of the virtual input device.
*/
@NonNull
public String getInputDeviceName() {
return mInputDeviceName;
}
void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mVendorId);
dest.writeInt(mProductId);
dest.writeInt(mAssociatedDisplayId);
dest.writeString8(mInputDeviceName);
}
/**
* A builder for {@link VirtualInputDeviceConfig}
*
* @param <T> The subclass to be built.
*/
@SuppressWarnings({"StaticFinalBuilder", "MissingBuildMethod"})
public abstract static class Builder<T extends Builder<T>> {
private int mVendorId;
private int mProductId;
private int mAssociatedDisplayId;
@NonNull
private String mInputDeviceName;
/** @see VirtualInputDeviceConfig#getVendorId(). */
@NonNull
public T setVendorId(int vendorId) {
mVendorId = vendorId;
return self();
}
/** @see VirtualInputDeviceConfig#getProductId(). */
@NonNull
public T setProductId(int productId) {
mProductId = productId;
return self();
}
/** @see VirtualInputDeviceConfig#getAssociatedDisplayId(). */
@NonNull
public T setAssociatedDisplayId(int displayId) {
mAssociatedDisplayId = displayId;
return self();
}
/** @see VirtualInputDeviceConfig#getInputDeviceName(). */
@NonNull
public T setInputDeviceName(@NonNull String deviceName) {
mInputDeviceName = deviceName;
return self();
}
/**
* Each subclass should return itself to allow the builder to chain properly
*/
T self() {
return (T) this;
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable VirtualKeyboardConfig;

View File

@@ -0,0 +1,77 @@
/*
* 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.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Configurations to create virtual keyboard.
*
* @hide
*/
@SystemApi
public final class VirtualKeyboardConfig extends VirtualInputDeviceConfig implements Parcelable {
@NonNull
public static final Creator<VirtualKeyboardConfig> CREATOR =
new Creator<VirtualKeyboardConfig>() {
@Override
public VirtualKeyboardConfig createFromParcel(Parcel in) {
return new VirtualKeyboardConfig(in);
}
@Override
public VirtualKeyboardConfig[] newArray(int size) {
return new VirtualKeyboardConfig[size];
}
};
private VirtualKeyboardConfig(@NonNull Builder builder) {
super(builder);
}
private VirtualKeyboardConfig(@NonNull Parcel in) {
super(in);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
}
/**
* Builder for creating a {@link VirtualKeyboardConfig}.
*/
public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
/**
* Builds the {@link VirtualKeyboardConfig} instance.
*/
@NonNull
public VirtualKeyboardConfig build() {
return new VirtualKeyboardConfig(this);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable VirtualMouseConfig;

View File

@@ -0,0 +1,75 @@
/*
* 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.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Configurations to create virtual mouse.
*
* @hide
*/
@SystemApi
public final class VirtualMouseConfig extends VirtualInputDeviceConfig implements Parcelable {
@NonNull
public static final Creator<VirtualMouseConfig> CREATOR = new Creator<VirtualMouseConfig>() {
@Override
public VirtualMouseConfig createFromParcel(Parcel in) {
return new VirtualMouseConfig(in);
}
@Override
public VirtualMouseConfig[] newArray(int size) {
return new VirtualMouseConfig[size];
}
};
private VirtualMouseConfig(@NonNull VirtualMouseConfig.Builder builder) {
super(builder);
}
private VirtualMouseConfig(@NonNull Parcel in) {
super(in);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
}
/**
* Builder for creating a {@link VirtualMouseConfig}.
*/
public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
/**
* Builds the {@link VirtualMouseConfig} instance.
*/
@NonNull
public VirtualMouseConfig build() {
return new VirtualMouseConfig(this);
}
}
}

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable VirtualTouchscreenConfig;

View File

@@ -0,0 +1,118 @@
/*
* 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.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Configurations to create virtual touchscreen.
*
* @hide
*/
@SystemApi
public final class VirtualTouchscreenConfig extends VirtualInputDeviceConfig implements Parcelable {
/** The touchscreen width in pixels. */
private final int mWidthInPixels;
/** The touchscreen height in pixels. */
private final int mHeightInPixels;
private VirtualTouchscreenConfig(@NonNull Builder builder) {
super(builder);
mWidthInPixels = builder.mWidthInPixels;
mHeightInPixels = builder.mHeightInPixels;
}
private VirtualTouchscreenConfig(@NonNull Parcel in) {
super(in);
mWidthInPixels = in.readInt();
mHeightInPixels = in.readInt();
}
/** Returns the touchscreen width in pixels. */
public int getWidthInPixels() {
return mWidthInPixels;
}
/** Returns the touchscreen height in pixels. */
public int getHeightInPixels() {
return mHeightInPixels;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeInt(mWidthInPixels);
dest.writeInt(mHeightInPixels);
}
@NonNull
public static final Creator<VirtualTouchscreenConfig> CREATOR =
new Creator<VirtualTouchscreenConfig>() {
@Override
public VirtualTouchscreenConfig createFromParcel(Parcel in) {
return new VirtualTouchscreenConfig(in);
}
@Override
public VirtualTouchscreenConfig[] newArray(int size) {
return new VirtualTouchscreenConfig[size];
}
};
/**
* Builder for creating a {@link VirtualTouchscreenConfig}.
*/
public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
private int mWidthInPixels;
private int mHeightInPixels;
/**
* @see VirtualTouchscreenConfig#getWidthInPixels().
*/
@NonNull
public Builder setWidthInPixels(int widthInPixels) {
mWidthInPixels = widthInPixels;
return this;
}
/**
* @see VirtualTouchscreenConfig#getHeightInPixels().
*/
@NonNull
public Builder setHeightInPixels(int heightInPixels) {
mHeightInPixels = heightInPixels;
return this;
}
/**
* Builds the {@link VirtualTouchscreenConfig} instance.
*/
@NonNull
public VirtualTouchscreenConfig build() {
return new VirtualTouchscreenConfig(this);
}
}
}

View File

@@ -19,7 +19,6 @@ package com.android.server.companion.virtual;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.StringDef;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputDeviceIdentifier;
@@ -178,13 +177,14 @@ class InputController {
int productId,
@NonNull IBinder deviceToken,
int displayId,
@NonNull Point screenSize) {
int height,
int width) {
final String phys = createPhys(PHYS_TYPE_TOUCHSCREEN);
try {
createDeviceInternal(InputDeviceDescriptor.TYPE_TOUCHSCREEN, deviceName, vendorId,
productId, deviceToken, displayId, phys,
() -> mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId,
phys, screenSize.y, screenSize.x));
phys, height, width));
} catch (DeviceCreationException e) {
throw new RuntimeException(
"Failed to create virtual touchscreen device '" + deviceName + "'.", e);
@@ -414,17 +414,25 @@ class InputController {
}
@VisibleForTesting
void addDeviceForTesting(IBinder deviceToken, int fd, int type, int displayId,
String phys, int inputDeviceId) {
void addDeviceForTesting(IBinder deviceToken, int fd, int type, int displayId, String phys,
int inputDeviceId) {
synchronized (mLock) {
mInputDeviceDescriptors.put(deviceToken,
new InputDeviceDescriptor(fd, () -> {}, type, displayId, phys,
inputDeviceId));
mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, () -> {
}, type, displayId, phys, inputDeviceId));
}
}
private static native int nativeOpenUinputDpad(String deviceName, int vendorId,
int productId, String phys);
@VisibleForTesting
Map<IBinder, InputDeviceDescriptor> getInputDeviceDescriptors() {
final Map<IBinder, InputDeviceDescriptor> inputDeviceDescriptors = new ArrayMap<>();
synchronized (mLock) {
inputDeviceDescriptors.putAll(mInputDeviceDescriptors);
}
return inputDeviceDescriptors;
}
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,

View File

@@ -44,14 +44,17 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.display.DisplayManager;
import android.hardware.input.VirtualDpadConfig;
import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualKeyboardConfig;
import android.hardware.input.VirtualMouseButtonEvent;
import android.hardware.input.VirtualMouseConfig;
import android.hardware.input.VirtualMouseRelativeEvent;
import android.hardware.input.VirtualMouseScrollEvent;
import android.hardware.input.VirtualTouchEvent;
import android.hardware.input.VirtualTouchscreenConfig;
import android.os.Binder;
import android.os.IBinder;
import android.os.Looper;
@@ -397,19 +400,12 @@ 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,
public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
"Permission required to create a virtual dpad");
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(displayId)) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
"Cannot create a virtual dpad for a display not associated with "
+ "this virtual device");
@@ -417,26 +413,19 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
final long ident = Binder.clearCallingIdentity();
try {
mInputController.createDpad(deviceName, vendorId, productId, deviceToken,
displayId);
mInputController.createDpad(config.getInputDeviceName(), config.getVendorId(),
config.getProductId(), deviceToken, config.getAssociatedDisplayId());
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@Override // Binder call
public void createVirtualKeyboard(
int displayId,
@NonNull String deviceName,
int vendorId,
int productId,
@NonNull IBinder deviceToken) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
"Permission required to create a virtual keyboard");
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(displayId)) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
"Cannot create a virtual keyboard for a display not associated with "
+ "this virtual device");
@@ -444,26 +433,19 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
final long ident = Binder.clearCallingIdentity();
try {
mInputController.createKeyboard(deviceName, vendorId, productId, deviceToken,
displayId);
mInputController.createKeyboard(config.getInputDeviceName(), config.getVendorId(),
config.getProductId(), deviceToken, config.getAssociatedDisplayId());
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@Override // Binder call
public void createVirtualMouse(
int displayId,
@NonNull String deviceName,
int vendorId,
int productId,
@NonNull IBinder deviceToken) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
"Permission required to create a virtual mouse");
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(displayId)) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
"Cannot create a virtual mouse for a display not associated with this "
+ "virtual device");
@@ -471,42 +453,38 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
final long ident = Binder.clearCallingIdentity();
try {
mInputController.createMouse(deviceName, vendorId, productId, deviceToken, displayId);
mInputController.createMouse(config.getInputDeviceName(), config.getVendorId(),
config.getProductId(), deviceToken, config.getAssociatedDisplayId());
} finally {
Binder.restoreCallingIdentity(ident);
}
}
@RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
@Override // Binder call
public void createVirtualTouchscreen(
int displayId,
@NonNull String deviceName,
int vendorId,
int productId,
@NonNull IBinder deviceToken,
@NonNull Point screenSize) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
public void createVirtualTouchscreen(VirtualTouchscreenConfig config,
@NonNull IBinder deviceToken) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
"Permission required to create a virtual touchscreen");
synchronized (mVirtualDeviceLock) {
if (!mVirtualDisplayIds.contains(displayId)) {
if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
throw new SecurityException(
"Cannot create a virtual touchscreen for a display not associated with "
+ "this virtual device");
}
}
if (screenSize.x <= 0 || screenSize.y <= 0) {
int screenHeightPixels = config.getHeightInPixels();
int screenWidthPixels = config.getWidthInPixels();
if (screenHeightPixels <= 0 || screenWidthPixels <= 0) {
throw new IllegalArgumentException(
"Cannot create a virtual touchscreen, screen dimensions must be positive. Got: "
+ screenSize);
+ "(" + screenWidthPixels + ", " + screenHeightPixels + ")");
}
final long ident = Binder.clearCallingIdentity();
try {
mInputController.createTouchscreen(deviceName, vendorId, productId,
deviceToken, displayId, screenSize);
mInputController.createTouchscreen(config.getInputDeviceName(), config.getVendorId(),
config.getProductId(), deviceToken, config.getAssociatedDisplayId(),
screenHeightPixels, screenWidthPixels);
} finally {
Binder.restoreCallingIdentity(ident);
}

View File

@@ -58,15 +58,18 @@ import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.graphics.Point;
import android.hardware.Sensor;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.IInputManager;
import android.hardware.input.VirtualDpadConfig;
import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualKeyboardConfig;
import android.hardware.input.VirtualMouseButtonEvent;
import android.hardware.input.VirtualMouseConfig;
import android.hardware.input.VirtualMouseRelativeEvent;
import android.hardware.input.VirtualMouseScrollEvent;
import android.hardware.input.VirtualTouchEvent;
import android.hardware.input.VirtualTouchscreenConfig;
import android.net.MacAddress;
import android.os.Binder;
import android.os.Handler;
@@ -135,7 +138,37 @@ public class VirtualDeviceManagerServiceTest {
private static final int SENSOR_HANDLE = 64;
private static final Binder BINDER = new Binder("binder");
private static final int FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000;
private static final int VIRTUAL_DEVICE_ID = 42;
private static final int VIRTUAL_DEVICE_ID = 42;
private static final VirtualDpadConfig DPAD_CONFIG =
new VirtualDpadConfig.Builder()
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.setInputDeviceName(DEVICE_NAME)
.setAssociatedDisplayId(DISPLAY_ID)
.build();
private static final VirtualKeyboardConfig KEYBOARD_CONFIG =
new VirtualKeyboardConfig.Builder()
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.setInputDeviceName(DEVICE_NAME)
.setAssociatedDisplayId(DISPLAY_ID)
.build();
private static final VirtualMouseConfig MOUSE_CONFIG =
new VirtualMouseConfig.Builder()
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.setInputDeviceName(DEVICE_NAME)
.setAssociatedDisplayId(DISPLAY_ID)
.build();
private static final VirtualTouchscreenConfig TOUCHSCREEN_CONFIG =
new VirtualTouchscreenConfig.Builder()
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.setInputDeviceName(DEVICE_NAME)
.setAssociatedDisplayId(DISPLAY_ID)
.setWidthInPixels(WIDTH)
.setHeightInPixels(HEIGHT)
.build();
private Context mContext;
private InputManagerMockHelper mInputManagerMockHelper;
@@ -477,63 +510,77 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void createVirtualDpad_noDisplay_failsSecurityException() {
assertThrows(
SecurityException.class,
() -> mDeviceImpl.createVirtualDpad(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
PRODUCT_ID, BINDER));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
}
@Test
public void createVirtualKeyboard_noDisplay_failsSecurityException() {
assertThrows(
SecurityException.class,
() -> mDeviceImpl.createVirtualKeyboard(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
PRODUCT_ID, BINDER));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
}
@Test
public void createVirtualMouse_noDisplay_failsSecurityException() {
assertThrows(
SecurityException.class,
() -> mDeviceImpl.createVirtualMouse(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
PRODUCT_ID, BINDER));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
}
@Test
public void createVirtualTouchscreen_noDisplay_failsSecurityException() {
assertThrows(
SecurityException.class,
() -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME,
VENDOR_ID, PRODUCT_ID, BINDER, new Point(WIDTH, HEIGHT)));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
}
@Test
public void createVirtualTouchscreen_zeroDisplayDimension_failsIllegalArgumentException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
Point size = new Point(0, 0);
final VirtualTouchscreenConfig zeroConfig =
new VirtualTouchscreenConfig.Builder()
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.setInputDeviceName(DEVICE_NAME)
.setAssociatedDisplayId(DISPLAY_ID)
.setWidthInPixels(0)
.setHeightInPixels(0)
.build();
assertThrows(IllegalArgumentException.class,
() -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
PRODUCT_ID, BINDER, size));
() -> mDeviceImpl.createVirtualTouchscreen(zeroConfig, BINDER));
}
@Test
public void createVirtualTouchscreen_negativeDisplayDimension_failsIllegalArgumentException() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
Point size = new Point(-100, -100);
final VirtualTouchscreenConfig negativeConfig =
new VirtualTouchscreenConfig.Builder()
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.setInputDeviceName(DEVICE_NAME)
.setAssociatedDisplayId(DISPLAY_ID)
.setWidthInPixels(-100)
.setHeightInPixels(-100)
.build();
assertThrows(IllegalArgumentException.class,
() -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
PRODUCT_ID, BINDER, size));
() -> mDeviceImpl.createVirtualTouchscreen(negativeConfig, BINDER));
}
@Test
public void createVirtualTouchscreen_positiveDisplayDimension_successful() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
Point size = new Point(600, 800);
mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER,
size);
VirtualTouchscreenConfig positiveConfig =
new VirtualTouchscreenConfig.Builder()
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.setInputDeviceName(DEVICE_NAME)
.setAssociatedDisplayId(DISPLAY_ID)
.setWidthInPixels(600)
.setHeightInPixels(800)
.build();
mDeviceImpl.createVirtualTouchscreen(positiveConfig, BINDER);
assertWithMessage(
"Virtual touchscreen should create input device descriptor on successful creation.")
.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
"Virtual touchscreen should create input device descriptor on successful creation"
+ ".").that(mInputController.getInputDeviceDescriptors()).isNotEmpty();
}
@Test
@@ -548,10 +595,8 @@ public class VirtualDeviceManagerServiceTest {
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));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
}
@Test
@@ -559,10 +604,8 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
assertThrows(
SecurityException.class,
() -> mDeviceImpl.createVirtualKeyboard(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
PRODUCT_ID, BINDER));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
}
@Test
@@ -570,10 +613,8 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
assertThrows(
SecurityException.class,
() -> mDeviceImpl.createVirtualMouse(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
PRODUCT_ID, BINDER));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
}
@Test
@@ -581,10 +622,8 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
assertThrows(
SecurityException.class,
() -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME,
VENDOR_ID, PRODUCT_ID, BINDER, new Point(WIDTH, HEIGHT)));
assertThrows(SecurityException.class,
() -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
}
@Test
@@ -619,21 +658,19 @@ public class VirtualDeviceManagerServiceTest {
@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());
mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER);
assertWithMessage("Virtual dpad should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).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);
mDeviceImpl.createVirtualKeyboard(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
BINDER);
assertWithMessage("Virtual keyboard should register fd when the display matches")
.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
assertWithMessage("Virtual keyboard should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).isNotEmpty();
verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME), eq(VENDOR_ID),
eq(PRODUCT_ID), anyString());
}
@@ -641,10 +678,9 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void createVirtualMouse_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
mDeviceImpl.createVirtualMouse(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
BINDER);
assertWithMessage("Virtual mouse should register fd when the display matches")
.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER);
assertWithMessage("Virtual mouse should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).isNotEmpty();
verify(mNativeWrapperMock).openUinputMouse(eq(DEVICE_NAME), eq(VENDOR_ID), eq(PRODUCT_ID),
anyString());
}
@@ -652,10 +688,9 @@ public class VirtualDeviceManagerServiceTest {
@Test
public void createVirtualTouchscreen_hasDisplay_obtainFileDescriptor() {
mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
BINDER, new Point(WIDTH, HEIGHT));
assertWithMessage("Virtual touchscreen should register fd when the display matches")
.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER);
assertWithMessage("Virtual touchscreen should register fd when the display matches").that(
mInputController.getInputDeviceDescriptors()).isNotEmpty();
verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME), eq(VENDOR_ID),
eq(PRODUCT_ID), anyString(), eq(HEIGHT), eq(WIDTH));
}
@@ -909,9 +944,28 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl.mVirtualDisplayIds.add(1);
mDeviceImpl.mVirtualDisplayIds.add(2);
mDeviceImpl.mVirtualDisplayIds.add(3);
mDeviceImpl.createVirtualMouse(1, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
mDeviceImpl.createVirtualMouse(2, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
mDeviceImpl.createVirtualMouse(3, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
VirtualMouseConfig config1 = new VirtualMouseConfig.Builder()
.setAssociatedDisplayId(1)
.setInputDeviceName(DEVICE_NAME)
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.build();
VirtualMouseConfig config2 = new VirtualMouseConfig.Builder()
.setAssociatedDisplayId(2)
.setInputDeviceName(DEVICE_NAME)
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.build();
VirtualMouseConfig config3 = new VirtualMouseConfig.Builder()
.setAssociatedDisplayId(3)
.setInputDeviceName(DEVICE_NAME)
.setVendorId(VENDOR_ID)
.setProductId(PRODUCT_ID)
.build();
mDeviceImpl.createVirtualMouse(config1, BINDER);
mDeviceImpl.createVirtualMouse(config2, BINDER);
mDeviceImpl.createVirtualMouse(config3, BINDER);
mDeviceImpl.setShowPointerIcon(false);
verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt());
verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt());