diff --git a/core/api/system-current.txt b/core/api/system-current.txt index c10504d9ee057..1d1d925ad018a 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -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, @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 CREATOR; + } + + public static final class VirtualDpadConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.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>); + 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> { + 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 CREATOR; + } + + public static final class VirtualKeyboardConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.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 CREATOR; + } + + public static final class VirtualMouseConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.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 CREATOR; + } + + public static final class VirtualTouchscreenConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.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 { diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl index 0837d85bb91c3..5c47ea2aa3f08 100644 --- a/core/java/android/companion/virtual/IVirtualDevice.aidl +++ b/core/java/android/companion/virtual/IVirtualDevice.aidl @@ -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); diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index 01b42bfa661c1..057dd8f687aec 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -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); } /** diff --git a/core/java/android/hardware/input/VirtualDpadConfig.aidl b/core/java/android/hardware/input/VirtualDpadConfig.aidl new file mode 100644 index 0000000000000..fac90f444a1ba --- /dev/null +++ b/core/java/android/hardware/input/VirtualDpadConfig.aidl @@ -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; diff --git a/core/java/android/hardware/input/VirtualDpadConfig.java b/core/java/android/hardware/input/VirtualDpadConfig.java new file mode 100644 index 0000000000000..d888dc0bffdfd --- /dev/null +++ b/core/java/android/hardware/input/VirtualDpadConfig.java @@ -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 CREATOR = new Creator() { + @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 { + + /** + * Builds the {@link VirtualDpadConfig} instance. + */ + @NonNull + public VirtualDpadConfig build() { + return new VirtualDpadConfig(this); + } + } +} diff --git a/core/java/android/hardware/input/VirtualInputDeviceConfig.java b/core/java/android/hardware/input/VirtualInputDeviceConfig.java new file mode 100644 index 0000000000000..d3dacc90d1b4b --- /dev/null +++ b/core/java/android/hardware/input/VirtualInputDeviceConfig.java @@ -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> 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 The subclass to be built. + */ + @SuppressWarnings({"StaticFinalBuilder", "MissingBuildMethod"}) + public abstract static class Builder> { + + 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; + } + } +} diff --git a/core/java/android/hardware/input/VirtualKeyboardConfig.aidl b/core/java/android/hardware/input/VirtualKeyboardConfig.aidl new file mode 100644 index 0000000000000..8772e239c5836 --- /dev/null +++ b/core/java/android/hardware/input/VirtualKeyboardConfig.aidl @@ -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; diff --git a/core/java/android/hardware/input/VirtualKeyboardConfig.java b/core/java/android/hardware/input/VirtualKeyboardConfig.java new file mode 100644 index 0000000000000..94638574c82d3 --- /dev/null +++ b/core/java/android/hardware/input/VirtualKeyboardConfig.java @@ -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 CREATOR = + new Creator() { + @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 { + /** + * Builds the {@link VirtualKeyboardConfig} instance. + */ + @NonNull + public VirtualKeyboardConfig build() { + return new VirtualKeyboardConfig(this); + } + } +} diff --git a/core/java/android/hardware/input/VirtualMouseConfig.aidl b/core/java/android/hardware/input/VirtualMouseConfig.aidl new file mode 100644 index 0000000000000..a0d5fb509d4f4 --- /dev/null +++ b/core/java/android/hardware/input/VirtualMouseConfig.aidl @@ -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; diff --git a/core/java/android/hardware/input/VirtualMouseConfig.java b/core/java/android/hardware/input/VirtualMouseConfig.java new file mode 100644 index 0000000000000..7ad5d0489faed --- /dev/null +++ b/core/java/android/hardware/input/VirtualMouseConfig.java @@ -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 CREATOR = new Creator() { + @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 { + + /** + * Builds the {@link VirtualMouseConfig} instance. + */ + @NonNull + public VirtualMouseConfig build() { + return new VirtualMouseConfig(this); + } + } +} diff --git a/core/java/android/hardware/input/VirtualTouchscreenConfig.aidl b/core/java/android/hardware/input/VirtualTouchscreenConfig.aidl new file mode 100644 index 0000000000000..e4b0edb7f0d18 --- /dev/null +++ b/core/java/android/hardware/input/VirtualTouchscreenConfig.aidl @@ -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; diff --git a/core/java/android/hardware/input/VirtualTouchscreenConfig.java b/core/java/android/hardware/input/VirtualTouchscreenConfig.java new file mode 100644 index 0000000000000..e358619baf710 --- /dev/null +++ b/core/java/android/hardware/input/VirtualTouchscreenConfig.java @@ -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 CREATOR = + new Creator() { + @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 { + 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); + } + } +} diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java index 02053cc7cfd3d..96c71e571f546 100644 --- a/services/companion/java/com/android/server/companion/virtual/InputController.java +++ b/services/companion/java/com/android/server/companion/virtual/InputController.java @@ -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 getInputDeviceDescriptors() { + final Map 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, diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java index 828f302e631ae..ef938107377d2 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java @@ -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); } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java index afaee04d7cec8..8d161909d1223 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java @@ -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());