1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.hardware.input;
18 
19 import android.annotation.NonNull;
20 import android.annotation.SystemApi;
21 import android.os.Parcel;
22 import android.view.Display;
23 
24 import java.nio.charset.StandardCharsets;
25 import java.util.Objects;
26 
27 /**
28  * Common configurations to create virtual input devices.
29  *
30  * @hide
31  */
32 @SystemApi
33 public abstract class VirtualInputDeviceConfig {
34 
35     /**
36      * The maximum length of a device name (in bytes in UTF-8 encoding).
37      *
38      * This limitation comes directly from uinput.
39      * See also UINPUT_MAX_NAME_SIZE in linux/uinput.h
40      */
41     private static final int DEVICE_NAME_MAX_LENGTH = 80;
42 
43     /** The vendor id uniquely identifies the company who manufactured the device. */
44     private final int mVendorId;
45     /**
46      * The product id uniquely identifies which product within the address space of a given vendor,
47      * identified by the device's vendor id.
48      */
49     private final int mProductId;
50     /** The associated display ID of the virtual input device. */
51     private final int mAssociatedDisplayId;
52     /** The name of the virtual input device. */
53     @NonNull
54     private final String mInputDeviceName;
55 
VirtualInputDeviceConfig(@onNull Builder<? extends Builder<?>> builder)56     protected VirtualInputDeviceConfig(@NonNull Builder<? extends Builder<?>> builder) {
57         mVendorId = builder.mVendorId;
58         mProductId = builder.mProductId;
59         mAssociatedDisplayId = builder.mAssociatedDisplayId;
60         mInputDeviceName = Objects.requireNonNull(builder.mInputDeviceName);
61 
62         if (mAssociatedDisplayId == Display.INVALID_DISPLAY) {
63             throw new IllegalArgumentException(
64                     "Display association is required for virtual input devices.");
65         }
66 
67         // Comparison is greater or equal because the device name must fit into a const char*
68         // including the \0-terminator. Therefore the actual number of bytes that can be used
69         // for device name is DEVICE_NAME_MAX_LENGTH - 1
70         if (mInputDeviceName.getBytes(StandardCharsets.UTF_8).length >= DEVICE_NAME_MAX_LENGTH) {
71             throw new IllegalArgumentException("Input device name exceeds maximum length of "
72                     + DEVICE_NAME_MAX_LENGTH + "bytes: " + mInputDeviceName);
73         }
74     }
75 
VirtualInputDeviceConfig(@onNull Parcel in)76     protected VirtualInputDeviceConfig(@NonNull Parcel in) {
77         mVendorId = in.readInt();
78         mProductId = in.readInt();
79         mAssociatedDisplayId = in.readInt();
80         mInputDeviceName = Objects.requireNonNull(in.readString8());
81     }
82 
83     /**
84      * The vendor id uniquely identifies the company who manufactured the device.
85      *
86      * @see Builder#setVendorId(int) (int)
87      */
getVendorId()88     public int getVendorId() {
89         return mVendorId;
90     }
91 
92     /**
93      * The product id uniquely identifies which product within the address space of a given vendor,
94      * identified by the device's vendor id.
95      *
96      * @see Builder#setProductId(int)
97      */
getProductId()98     public int getProductId() {
99         return mProductId;
100     }
101 
102     /**
103      * The associated display ID of the virtual input device.
104      *
105      * @see Builder#setAssociatedDisplayId(int)
106      */
getAssociatedDisplayId()107     public int getAssociatedDisplayId() {
108         return mAssociatedDisplayId;
109     }
110 
111     /**
112      * The name of the virtual input device.
113      *
114      * @see Builder#setInputDeviceName(String)
115      */
116     @NonNull
getInputDeviceName()117     public String getInputDeviceName() {
118         return mInputDeviceName;
119     }
120 
writeToParcel(@onNull Parcel dest, int flags)121     void writeToParcel(@NonNull Parcel dest, int flags) {
122         dest.writeInt(mVendorId);
123         dest.writeInt(mProductId);
124         dest.writeInt(mAssociatedDisplayId);
125         dest.writeString8(mInputDeviceName);
126     }
127 
128     @Override
toString()129     public String toString() {
130         return getClass().getName() + "( "
131                 + " name=" + mInputDeviceName
132                 + " vendorId=" + mVendorId
133                 + " productId=" + mProductId
134                 + " associatedDisplayId=" + mAssociatedDisplayId
135                 + additionalFieldsToString() + ")";
136     }
137 
138     /** @hide */
139     @NonNull
additionalFieldsToString()140     String additionalFieldsToString() {
141         return "";
142     }
143 
144     /**
145      * A builder for {@link VirtualInputDeviceConfig}
146      *
147      * @param <T> The subclass to be built.
148      */
149     @SuppressWarnings({"StaticFinalBuilder", "MissingBuildMethod"})
150     public abstract static class Builder<T extends Builder<T>> {
151 
152         private int mVendorId;
153         private int mProductId;
154         private int mAssociatedDisplayId = Display.INVALID_DISPLAY;
155         private String mInputDeviceName;
156 
157         /**
158          * Sets the vendor id of the device, identifying the company who manufactured the device.
159          */
160         @NonNull
setVendorId(int vendorId)161         public T setVendorId(int vendorId) {
162             mVendorId = vendorId;
163             return self();
164         }
165 
166 
167         /**
168          * Sets the product id of the device, uniquely identifying the device within the address
169          * space of a given vendor, identified by the device's vendor id.
170          */
171         @NonNull
setProductId(int productId)172         public T setProductId(int productId) {
173             mProductId = productId;
174             return self();
175         }
176 
177         /**
178          * Sets the associated display ID of the virtual input device. Required.
179          *
180          * <p>The input device is restricted to the display with the given ID and may not send
181          * events to any other display.</p>
182          */
183         @NonNull
setAssociatedDisplayId(int displayId)184         public T setAssociatedDisplayId(int displayId) {
185             mAssociatedDisplayId = displayId;
186             return self();
187         }
188 
189         /**
190          * Sets the name of the virtual input device. Required.
191          *
192          * <p>The name must be unique among all input devices that belong to the same virtual
193          * device.</p>
194          *
195          * <p>The maximum allowed length of the name is 80 bytes in UTF-8 encoding, enforced by
196          * {@code UINPUT_MAX_NAME_SIZE}.</p>
197          */
198         @NonNull
setInputDeviceName(@onNull String deviceName)199         public T setInputDeviceName(@NonNull String deviceName) {
200             mInputDeviceName = Objects.requireNonNull(deviceName);
201             return self();
202         }
203 
204         /**
205          * Each subclass should return itself to allow the builder to chain properly
206          */
self()207         T self() {
208             return (T) this;
209         }
210     }
211 }
212