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

Commit c4cf03b1 authored by Christine Franks's avatar Christine Franks
Browse files

Remote input interfaces, events, and injection

Bug: 204081582
CTS-Coverage-Bug: 208247880
Test: atest FrameworksServicesTests:VirtualDeviceManagerServiceTest
and atest FrameworksCoreTests:android.hardware.input

Change-Id: Ic10e62b0d95d563aed59ed9bb8caba6d506176b7
parent a2cb2b1f
Loading
Loading
Loading
Loading
+121 −0
Original line number Diff line number Diff line
@@ -3889,6 +3889,127 @@ package android.hardware.hdmi {
}
package android.hardware.input {
  public final class VirtualKeyEvent implements android.os.Parcelable {
    method public int describeContents();
    method public int getAction();
    method public int getKeyCode();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field public static final int ACTION_DOWN = 0; // 0x0
    field public static final int ACTION_UP = 1; // 0x1
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualKeyEvent> CREATOR;
  }
  public static final class VirtualKeyEvent.Builder {
    ctor public VirtualKeyEvent.Builder();
    method @NonNull public android.hardware.input.VirtualKeyEvent build();
    method @NonNull public android.hardware.input.VirtualKeyEvent.Builder setAction(int);
    method @NonNull public android.hardware.input.VirtualKeyEvent.Builder setKeyCode(int);
  }
  public class VirtualKeyboard implements java.io.Closeable {
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
  }
  public class VirtualMouse implements java.io.Closeable {
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendButtonEvent(@NonNull android.hardware.input.VirtualMouseButtonEvent);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendRelativeEvent(@NonNull android.hardware.input.VirtualMouseRelativeEvent);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendScrollEvent(@NonNull android.hardware.input.VirtualMouseScrollEvent);
  }
  public final class VirtualMouseButtonEvent implements android.os.Parcelable {
    method public int describeContents();
    method public int getAction();
    method public int getButtonCode();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field public static final int ACTION_BUTTON_PRESS = 11; // 0xb
    field public static final int ACTION_BUTTON_RELEASE = 12; // 0xc
    field public static final int BUTTON_BACK = 8; // 0x8
    field public static final int BUTTON_FORWARD = 16; // 0x10
    field public static final int BUTTON_PRIMARY = 1; // 0x1
    field public static final int BUTTON_SECONDARY = 2; // 0x2
    field public static final int BUTTON_TERTIARY = 4; // 0x4
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualMouseButtonEvent> CREATOR;
  }
  public static final class VirtualMouseButtonEvent.Builder {
    ctor public VirtualMouseButtonEvent.Builder();
    method @NonNull public android.hardware.input.VirtualMouseButtonEvent build();
    method @NonNull public android.hardware.input.VirtualMouseButtonEvent.Builder setAction(int);
    method @NonNull public android.hardware.input.VirtualMouseButtonEvent.Builder setButtonCode(int);
  }
  public final class VirtualMouseRelativeEvent implements android.os.Parcelable {
    method public int describeContents();
    method public float getRelativeX();
    method public float getRelativeY();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualMouseRelativeEvent> CREATOR;
  }
  public static final class VirtualMouseRelativeEvent.Builder {
    ctor public VirtualMouseRelativeEvent.Builder();
    method @NonNull public android.hardware.input.VirtualMouseRelativeEvent build();
    method @NonNull public android.hardware.input.VirtualMouseRelativeEvent.Builder setRelativeX(float);
    method @NonNull public android.hardware.input.VirtualMouseRelativeEvent.Builder setRelativeY(float);
  }
  public final class VirtualMouseScrollEvent implements android.os.Parcelable {
    method public int describeContents();
    method public float getXAxisMovement();
    method public float getYAxisMovement();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualMouseScrollEvent> CREATOR;
  }
  public static final class VirtualMouseScrollEvent.Builder {
    ctor public VirtualMouseScrollEvent.Builder();
    method @NonNull public android.hardware.input.VirtualMouseScrollEvent build();
    method @NonNull public android.hardware.input.VirtualMouseScrollEvent.Builder setXAxisMovement(@FloatRange(from=-1.0F, to=1.0f) float);
    method @NonNull public android.hardware.input.VirtualMouseScrollEvent.Builder setYAxisMovement(@FloatRange(from=-1.0F, to=1.0f) float);
  }
  public final class VirtualTouchEvent implements android.os.Parcelable {
    method public int describeContents();
    method public int getAction();
    method public float getMajorAxisSize();
    method public int getPointerId();
    method public float getPressure();
    method public int getToolType();
    method public float getX();
    method public float getY();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field public static final int ACTION_CANCEL = 3; // 0x3
    field public static final int ACTION_DOWN = 0; // 0x0
    field public static final int ACTION_MOVE = 2; // 0x2
    field public static final int ACTION_UP = 1; // 0x1
    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualTouchEvent> CREATOR;
    field public static final int TOOL_TYPE_FINGER = 1; // 0x1
    field public static final int TOOL_TYPE_PALM = 5; // 0x5
  }
  public static final class VirtualTouchEvent.Builder {
    ctor public VirtualTouchEvent.Builder();
    method @NonNull public android.hardware.input.VirtualTouchEvent build();
    method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setAction(int);
    method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setMajorAxisSize(@FloatRange(from=0.0f) float);
    method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setPointerId(int);
    method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setPressure(@FloatRange(from=0.0f) float);
    method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setToolType(int);
    method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setX(float);
    method @NonNull public android.hardware.input.VirtualTouchEvent.Builder setY(float);
  }
  public class VirtualTouchscreen implements java.io.Closeable {
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendTouchEvent(@NonNull android.hardware.input.VirtualTouchEvent);
  }
}
package android.hardware.lights {
  public final class LightState implements android.os.Parcelable {
+32 −0
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@

package android.companion.virtual;

import android.graphics.Point;
import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualMouseButtonEvent;
import android.hardware.input.VirtualMouseRelativeEvent;
import android.hardware.input.VirtualMouseScrollEvent;
import android.hardware.input.VirtualTouchEvent;

/**
 * Interface for a virtual device.
 *
@@ -34,4 +41,29 @@ interface IVirtualDevice {
     * Closes the virtual device and frees all associated resources.
     */
    void close();
    void createVirtualKeyboard(
            int displayId,
            String inputDeviceName,
            int vendorId,
            int productId,
            IBinder token);
    void createVirtualMouse(
            int displayId,
            String inputDeviceName,
            int vendorId,
            int productId,
            IBinder token);
    void createVirtualTouchscreen(
            int displayId,
            String inputDeviceName,
            int vendorId,
            int productId,
            IBinder token,
            in Point screenSize);
    void unregisterInputDevice(IBinder token);
    boolean sendKeyEvent(IBinder token, in VirtualKeyEvent event);
    boolean sendButtonEvent(IBinder token, in VirtualMouseButtonEvent event);
    boolean sendRelativeEvent(IBinder token, in VirtualMouseRelativeEvent event);
    boolean sendScrollEvent(IBinder token, in VirtualMouseScrollEvent event);
    boolean sendTouchEvent(IBinder token, in VirtualTouchEvent event);
}
+91 −0
Original line number Diff line number Diff line
@@ -23,7 +23,13 @@ import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.companion.AssociationInfo;
import android.content.Context;
import android.graphics.Point;
import android.hardware.display.VirtualDisplay;
import android.hardware.input.VirtualKeyboard;
import android.hardware.input.VirtualMouse;
import android.hardware.input.VirtualTouchscreen;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;

/**
@@ -73,6 +79,8 @@ public final class VirtualDeviceManager {
     * A virtual device has its own virtual display, audio output, microphone, and camera etc. The
     * creator of a virtual device can take the output from the virtual display and stream it over
     * to another device, and inject input events that are received from the remote device.
     *
     * TODO(b/204081582): Consider using a builder pattern for the input APIs.
     */
    public static class VirtualDevice implements AutoCloseable {

@@ -95,5 +103,88 @@ public final class VirtualDeviceManager {
                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 vendor id
         * @param productId the product id
         * @hide
         */
        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
        @NonNull
        public VirtualKeyboard createVirtualKeyboard(
                @NonNull VirtualDisplay display,
                @NonNull String inputDeviceName,
                int vendorId,
                int productId) {
            try {
                final IBinder token = new Binder(
                        "android.hardware.input.VirtualKeyboard:" + inputDeviceName);
                mVirtualDevice.createVirtualKeyboard(display.getDisplay().getDisplayId(),
                        inputDeviceName, vendorId, productId, token);
                return new VirtualKeyboard(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 inputDeviceName the name to call this input device
         * @param vendorId the vendor id
         * @param productId the product id
         * @hide
         */
        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
        @NonNull
        public VirtualMouse createVirtualMouse(
                @NonNull VirtualDisplay display,
                @NonNull String inputDeviceName,
                int vendorId,
                int productId) {
            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);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Creates a virtual touchscreen.
         *
         * @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 vendor id
         * @param productId the product id
         * @hide
         */
        @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();
            }
        }
    }
}
+19 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.hardware.input;

parcelable VirtualKeyEvent;
 No newline at end of file
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.hardware.input;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.KeyEvent;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * An event describing a keyboard interaction originating from a remote device.
 *
 * When the user presses a key, an {@code ACTION_DOWN} event should be reported. When the user
 * releases the key, an {@code ACTION_UP} event should be reported.
 *
 * See {@link android.view.KeyEvent}.
 *
 * @hide
 */
@SystemApi
public final class VirtualKeyEvent implements Parcelable {

    /** @hide */
    public static final int ACTION_UNKNOWN = -1;
    /** Action indicating the given key has been pressed. */
    public static final int ACTION_DOWN = KeyEvent.ACTION_DOWN;
    /** Action indicating the previously pressed key has been lifted. */
    public static final int ACTION_UP = KeyEvent.ACTION_UP;

    /** @hide */
    @IntDef(prefix = { "ACTION_" }, value = {
            ACTION_UNKNOWN,
            ACTION_DOWN,
            ACTION_UP,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Action {
    }

    private final @Action int mAction;
    private final int mKeyCode;

    private VirtualKeyEvent(@Action int action, int keyCode) {
        mAction = action;
        mKeyCode = keyCode;
    }

    private VirtualKeyEvent(@NonNull Parcel parcel) {
        mAction = parcel.readInt();
        mKeyCode = parcel.readInt();
    }

    @Override
    public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
        parcel.writeInt(mAction);
        parcel.writeInt(mKeyCode);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * Returns the key code associated with this event.
     */
    public int getKeyCode() {
        return mKeyCode;
    }

    /**
     * Returns the action associated with this event.
     */
    public @Action int getAction() {
        return mAction;
    }

    /**
     * Builder for {@link VirtualKeyEvent}.
     */
    public static final class Builder {

        private @Action int mAction = ACTION_UNKNOWN;
        private int mKeyCode = -1;

        /**
         * Creates a {@link VirtualKeyEvent} object with the current builder configuration.
         */
        public @NonNull VirtualKeyEvent build() {
            if (mAction == ACTION_UNKNOWN || mKeyCode == -1) {
                throw new IllegalArgumentException(
                        "Cannot build virtual key event with unset fields");
            }
            return new VirtualKeyEvent(mAction, mKeyCode);
        }

        /**
         * Sets the Android key code of the event. The set of allowed characters include digits 0-9,
         * characters A-Z, and standard punctuation, as well as numpad keys, function keys F1-F12,
         * and meta keys (caps lock, shift, etc.).
         *
         * @return this builder, to allow for chaining of calls
         */
        public @NonNull Builder setKeyCode(int keyCode) {
            mKeyCode = keyCode;
            return this;
        }

        /**
         * Sets the action of the event.
         *
         * @return this builder, to allow for chaining of calls
         */
        public @NonNull Builder setAction(@Action int action) {
            if (action != ACTION_DOWN && action != ACTION_UP) {
                throw new IllegalArgumentException("Unsupported action type");
            }
            mAction = action;
            return this;
        }
    }

    public static final @NonNull Parcelable.Creator<VirtualKeyEvent> CREATOR =
            new Parcelable.Creator<VirtualKeyEvent>() {
        public VirtualKeyEvent createFromParcel(Parcel source) {
            return new VirtualKeyEvent(source);
        }

        public VirtualKeyEvent[] newArray(int size) {
            return new VirtualKeyEvent[size];
        }
    };
}
Loading