Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b05edb2f authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

Virtual input API improvements

 - Do not crash when closing a closed input device
 - Do crash when the input device failed to be created
 - Log the device name when an event failed to be sent
 - Log the device name when closing the device
 - Remove redundant checks already covered in the configs
 - Add missing checks in the configs
 - Add missing API documentation

Fix: 306679262
Fix: 268457357
Test: CTS

Change-Id: Icbe521a7ba46c460d3b98286b2c4c05ce6e8e2c6
parent fe810dc2
Loading
Loading
Loading
Loading
+5 −1
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.SystemApi;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDevice;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
import android.view.KeyEvent;


import java.util.Arrays;
import java.util.Arrays;
@@ -80,7 +81,10 @@ public class VirtualDpad extends VirtualInputDevice {
                                + event.getKeyCode()
                                + event.getKeyCode()
                                + " sent to a VirtualDpad input device.");
                                + " sent to a VirtualDpad input device.");
            }
            }
            mVirtualDevice.sendDpadKeyEvent(mToken, event);
            if (!mVirtualDevice.sendDpadKeyEvent(mToken, event)) {
                Log.w(TAG, "Failed to send key event to virtual dpad "
                        + mConfig.getInputDeviceName());
            }
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
        }
        }
+4 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import android.annotation.RequiresPermission;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDevice;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;


import java.io.Closeable;
import java.io.Closeable;


@@ -32,6 +33,8 @@ import java.io.Closeable;
 */
 */
abstract class VirtualInputDevice implements Closeable {
abstract class VirtualInputDevice implements Closeable {


    protected static final String TAG = "VirtualInputDevice";

    /**
    /**
     * The virtual device to which this VirtualInputDevice belongs to.
     * The virtual device to which this VirtualInputDevice belongs to.
     */
     */
@@ -67,6 +70,7 @@ abstract class VirtualInputDevice implements Closeable {
    @Override
    @Override
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    public void close() {
    public void close() {
        Log.d(TAG, "Closing virtual input device " + mConfig.getInputDeviceName());
        try {
        try {
            mVirtualDevice.unregisterInputDevice(mToken);
            mVirtualDevice.unregisterInputDevice(mToken);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
+60 −9
Original line number Original line Diff line number Diff line
@@ -19,6 +19,10 @@ package android.hardware.input;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcel;
import android.view.Display;

import java.nio.charset.StandardCharsets;
import java.util.Objects;


/**
/**
 * Common configurations to create virtual input devices.
 * Common configurations to create virtual input devices.
@@ -27,6 +31,15 @@ import android.os.Parcel;
 */
 */
@SystemApi
@SystemApi
public abstract class VirtualInputDeviceConfig {
public abstract class VirtualInputDeviceConfig {

    /**
     * The maximum length of a device name (in bytes in UTF-8 encoding).
     *
     * This limitation comes directly from uinput.
     * See also UINPUT_MAX_NAME_SIZE in linux/uinput.h
     */
    private static final int DEVICE_NAME_MAX_LENGTH = 80;

    /** The vendor id uniquely identifies the company who manufactured the device. */
    /** The vendor id uniquely identifies the company who manufactured the device. */
    private final int mVendorId;
    private final int mVendorId;
    /**
    /**
@@ -44,18 +57,33 @@ public abstract class VirtualInputDeviceConfig {
        mVendorId = builder.mVendorId;
        mVendorId = builder.mVendorId;
        mProductId = builder.mProductId;
        mProductId = builder.mProductId;
        mAssociatedDisplayId = builder.mAssociatedDisplayId;
        mAssociatedDisplayId = builder.mAssociatedDisplayId;
        mInputDeviceName = builder.mInputDeviceName;
        mInputDeviceName = Objects.requireNonNull(builder.mInputDeviceName);

        if (mAssociatedDisplayId == Display.INVALID_DISPLAY) {
            throw new IllegalArgumentException(
                    "Display association is required for virtual input devices.");
        }

        // Comparison is greater or equal because the device name must fit into a const char*
        // including the \0-terminator. Therefore the actual number of bytes that can be used
        // for device name is DEVICE_NAME_MAX_LENGTH - 1
        if (mInputDeviceName.getBytes(StandardCharsets.UTF_8).length >= DEVICE_NAME_MAX_LENGTH) {
            throw new IllegalArgumentException("Input device name exceeds maximum length of "
                    + DEVICE_NAME_MAX_LENGTH + "bytes: " + mInputDeviceName);
        }
    }
    }


    protected VirtualInputDeviceConfig(@NonNull Parcel in) {
    protected VirtualInputDeviceConfig(@NonNull Parcel in) {
        mVendorId = in.readInt();
        mVendorId = in.readInt();
        mProductId = in.readInt();
        mProductId = in.readInt();
        mAssociatedDisplayId = in.readInt();
        mAssociatedDisplayId = in.readInt();
        mInputDeviceName = in.readString8();
        mInputDeviceName = Objects.requireNonNull(in.readString8());
    }
    }


    /**
    /**
     * The vendor id uniquely identifies the company who manufactured the device.
     * The vendor id uniquely identifies the company who manufactured the device.
     *
     * @see Builder#setVendorId(int) (int)
     */
     */
    public int getVendorId() {
    public int getVendorId() {
        return mVendorId;
        return mVendorId;
@@ -64,6 +92,8 @@ public abstract class VirtualInputDeviceConfig {
    /**
    /**
     * The product id uniquely identifies which product within the address space of a given vendor,
     * The product id uniquely identifies which product within the address space of a given vendor,
     * identified by the device's vendor id.
     * identified by the device's vendor id.
     *
     * @see Builder#setProductId(int)
     */
     */
    public int getProductId() {
    public int getProductId() {
        return mProductId;
        return mProductId;
@@ -71,6 +101,8 @@ public abstract class VirtualInputDeviceConfig {


    /**
    /**
     * The associated display ID of the virtual input device.
     * The associated display ID of the virtual input device.
     *
     * @see Builder#setAssociatedDisplayId(int)
     */
     */
    public int getAssociatedDisplayId() {
    public int getAssociatedDisplayId() {
        return mAssociatedDisplayId;
        return mAssociatedDisplayId;
@@ -78,6 +110,8 @@ public abstract class VirtualInputDeviceConfig {


    /**
    /**
     * The name of the virtual input device.
     * The name of the virtual input device.
     *
     * @see Builder#setInputDeviceName(String)
     */
     */
    @NonNull
    @NonNull
    public String getInputDeviceName() {
    public String getInputDeviceName() {
@@ -117,11 +151,12 @@ public abstract class VirtualInputDeviceConfig {


        private int mVendorId;
        private int mVendorId;
        private int mProductId;
        private int mProductId;
        private int mAssociatedDisplayId;
        private int mAssociatedDisplayId = Display.INVALID_DISPLAY;
        @NonNull
        private String mInputDeviceName;
        private String mInputDeviceName;


        /** @see VirtualInputDeviceConfig#getVendorId(). */
        /**
         * Sets the vendor id of the device, identifying the company who manufactured the device.
         */
        @NonNull
        @NonNull
        public T setVendorId(int vendorId) {
        public T setVendorId(int vendorId) {
            mVendorId = vendorId;
            mVendorId = vendorId;
@@ -129,24 +164,40 @@ public abstract class VirtualInputDeviceConfig {
        }
        }




        /** @see VirtualInputDeviceConfig#getProductId(). */
        /**
         * Sets the product id of the device, uniquely identifying the device within the address
         * space of a given vendor, identified by the device's vendor id.
         */
        @NonNull
        @NonNull
        public T setProductId(int productId) {
        public T setProductId(int productId) {
            mProductId = productId;
            mProductId = productId;
            return self();
            return self();
        }
        }


        /** @see VirtualInputDeviceConfig#getAssociatedDisplayId(). */
        /**
         * Sets the associated display ID of the virtual input device. Required.
         *
         * <p>The input device is restricted to the display with the given ID and may not send
         * events to any other display.</p>
         */
        @NonNull
        @NonNull
        public T setAssociatedDisplayId(int displayId) {
        public T setAssociatedDisplayId(int displayId) {
            mAssociatedDisplayId = displayId;
            mAssociatedDisplayId = displayId;
            return self();
            return self();
        }
        }


        /** @see VirtualInputDeviceConfig#getInputDeviceName(). */
        /**
         * Sets the name of the virtual input device. Required.
         *
         * <p>The name must be unique among all input devices that belong to the same virtual
         * device.</p>
         *
         * <p>The maximum allowed length of the name is 80 bytes in UTF-8 encoding, enforced by
         * {@code UINPUT_MAX_NAME_SIZE}.</p>
         */
        @NonNull
        @NonNull
        public T setInputDeviceName(@NonNull String deviceName) {
        public T setInputDeviceName(@NonNull String deviceName) {
            mInputDeviceName = deviceName;
            mInputDeviceName = Objects.requireNonNull(deviceName);
            return self();
            return self();
        }
        }


+5 −1
Original line number Original line Diff line number Diff line
@@ -22,6 +22,7 @@ import android.annotation.SystemApi;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDevice;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.view.KeyEvent;
import android.view.KeyEvent;


/**
/**
@@ -57,7 +58,10 @@ public class VirtualKeyboard extends VirtualInputDevice {
                    "Unsupported key code " + event.getKeyCode()
                    "Unsupported key code " + event.getKeyCode()
                        + " sent to a VirtualKeyboard input device.");
                        + " sent to a VirtualKeyboard input device.");
            }
            }
            mVirtualDevice.sendKeyEvent(mToken, event);
            if (!mVirtualDevice.sendKeyEvent(mToken, event)) {
                Log.w(TAG, "Failed to send key event to virtual keyboard "
                        + mConfig.getInputDeviceName());
            }
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
        }
        }
+13 −3
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.companion.virtual.IVirtualDevice;
import android.graphics.PointF;
import android.graphics.PointF;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
import android.view.MotionEvent;


/**
/**
@@ -52,7 +53,10 @@ public class VirtualMouse extends VirtualInputDevice {
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    public void sendButtonEvent(@NonNull VirtualMouseButtonEvent event) {
    public void sendButtonEvent(@NonNull VirtualMouseButtonEvent event) {
        try {
        try {
            mVirtualDevice.sendButtonEvent(mToken, event);
            if (!mVirtualDevice.sendButtonEvent(mToken, event)) {
                Log.w(TAG, "Failed to send button event to virtual mouse "
                        + mConfig.getInputDeviceName());
            }
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
        }
        }
@@ -69,7 +73,10 @@ public class VirtualMouse extends VirtualInputDevice {
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    public void sendScrollEvent(@NonNull VirtualMouseScrollEvent event) {
    public void sendScrollEvent(@NonNull VirtualMouseScrollEvent event) {
        try {
        try {
            mVirtualDevice.sendScrollEvent(mToken, event);
            if (!mVirtualDevice.sendScrollEvent(mToken, event)) {
                Log.w(TAG, "Failed to send scroll event to virtual mouse "
                        + mConfig.getInputDeviceName());
            }
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
        }
        }
@@ -85,7 +92,10 @@ public class VirtualMouse extends VirtualInputDevice {
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
    public void sendRelativeEvent(@NonNull VirtualMouseRelativeEvent event) {
    public void sendRelativeEvent(@NonNull VirtualMouseRelativeEvent event) {
        try {
        try {
            mVirtualDevice.sendRelativeEvent(mToken, event);
            if (!mVirtualDevice.sendRelativeEvent(mToken, event)) {
                Log.w(TAG, "Failed to send relative event to virtual mouse "
                        + mConfig.getInputDeviceName());
            }
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
        }
        }
Loading