1 /* 2 * Copyright (C) 2020 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 com.android.commands.uinput; 18 19 import android.annotation.Nullable; 20 import android.util.SparseArray; 21 22 import java.util.Arrays; 23 import java.util.Objects; 24 25 import src.com.android.commands.uinput.InputAbsInfo; 26 27 /** 28 * An event is a JSON file defined action event to instruct uinput to perform a command like 29 * device registration or uinput events injection. 30 */ 31 public class Event { 32 private static final String TAG = "UinputEvent"; 33 34 public enum Command { 35 REGISTER, 36 DELAY, 37 INJECT, 38 SYNC, 39 UPDATE_TIME_BASE, 40 } 41 42 // Constants representing evdev event types, from include/uapi/linux/input-event-codes.h in the 43 // kernel. 44 public static final int EV_SYN = 0x00; 45 public static final int EV_KEY = 0x01; 46 public static final int EV_REL = 0x02; 47 public static final int EV_ABS = 0x03; 48 public static final int EV_MSC = 0x04; 49 public static final int EV_SW = 0x05; 50 public static final int EV_LED = 0x11; 51 public static final int EV_SND = 0x12; 52 public static final int EV_FF = 0x15; 53 54 public enum UinputControlCode { 55 UI_SET_EVBIT(100), 56 UI_SET_KEYBIT(101), 57 UI_SET_RELBIT(102), 58 UI_SET_ABSBIT(103), 59 UI_SET_MSCBIT(104), 60 UI_SET_LEDBIT(105), 61 UI_SET_SNDBIT(106), 62 UI_SET_FFBIT(107), 63 UI_SET_SWBIT(109), 64 UI_SET_PROPBIT(110); 65 66 private final int mValue; 67 UinputControlCode(int value)68 UinputControlCode(int value) { 69 this.mValue = value; 70 } 71 getValue()72 public int getValue() { 73 return mValue; 74 } 75 76 /** 77 * Returns the control code for the given evdev event type, or {@code null} if there is no 78 * control code for that type. 79 */ forEventType(int eventType)80 public static @Nullable UinputControlCode forEventType(int eventType) { 81 return switch (eventType) { 82 case EV_KEY -> UI_SET_KEYBIT; 83 case EV_REL -> UI_SET_RELBIT; 84 case EV_ABS -> UI_SET_ABSBIT; 85 case EV_MSC -> UI_SET_MSCBIT; 86 case EV_SW -> UI_SET_SWBIT; 87 case EV_LED -> UI_SET_LEDBIT; 88 case EV_SND -> UI_SET_SNDBIT; 89 case EV_FF -> UI_SET_FFBIT; 90 default -> null; 91 }; 92 } 93 } 94 95 private int mId; 96 private Command mCommand; 97 private String mName; 98 private int mVendorId; 99 private int mProductId; 100 private int mVersionId; 101 private int mBusId; 102 private int[] mInjections; 103 private long mTimestampOffsetMicros = -1; 104 private SparseArray<int[]> mConfiguration; 105 private long mDurationNanos; 106 private int mFfEffectsMax = 0; 107 private String mInputPort; 108 private SparseArray<InputAbsInfo> mAbsInfo; 109 private String mSyncToken; 110 getId()111 public int getId() { 112 return mId; 113 } 114 getCommand()115 public Command getCommand() { 116 return mCommand; 117 } 118 getName()119 public String getName() { 120 return mName; 121 } 122 getVendorId()123 public int getVendorId() { 124 return mVendorId; 125 } 126 getProductId()127 public int getProductId() { 128 return mProductId; 129 } 130 getVersionId()131 public int getVersionId() { 132 return mVersionId; 133 } 134 getBus()135 public int getBus() { 136 return mBusId; 137 } 138 getInjections()139 public int[] getInjections() { 140 return mInjections; 141 } 142 143 /** 144 * Returns the number of microseconds that should be added to the previous {@code INJECT} 145 * event's timestamp to produce the timestamp for this {@code INJECT} event. A value of -1 146 * indicates that the current timestamp should be used instead. 147 */ getTimestampOffsetMicros()148 public long getTimestampOffsetMicros() { 149 return mTimestampOffsetMicros; 150 } 151 152 /** 153 * Returns a {@link SparseArray} describing the event codes that should be registered for the 154 * device. The keys are uinput ioctl codes (such as those returned from {@link 155 * UinputControlCode#getValue()}, while the values are arrays of event codes to be enabled with 156 * those ioctls. For example, key 101 (corresponding to {@link UinputControlCode#UI_SET_KEYBIT}) 157 * could have values 0x110 ({@code BTN_LEFT}), 0x111 ({@code BTN_RIGHT}), and 0x112 158 * ({@code BTN_MIDDLE}). 159 */ getConfiguration()160 public SparseArray<int[]> getConfiguration() { 161 return mConfiguration; 162 } 163 getDurationNanos()164 public long getDurationNanos() { 165 return mDurationNanos; 166 } 167 getFfEffectsMax()168 public int getFfEffectsMax() { 169 return mFfEffectsMax; 170 } 171 getAbsInfo()172 public SparseArray<InputAbsInfo> getAbsInfo() { 173 return mAbsInfo; 174 } 175 getPort()176 public String getPort() { 177 return mInputPort; 178 } 179 getSyncToken()180 public String getSyncToken() { 181 return mSyncToken; 182 } 183 184 /** 185 * Convert an event to String. 186 */ toString()187 public String toString() { 188 return "Event{id=" + mId 189 + ", command=" + mCommand 190 + ", name=" + mName 191 + ", vid=" + mVendorId 192 + ", pid=" + mProductId 193 + ", busId=" + mBusId 194 + ", events=" + Arrays.toString(mInjections) 195 + ", configuration=" + mConfiguration 196 + ", duration=" + mDurationNanos + "ns" 197 + ", ff_effects_max=" + mFfEffectsMax 198 + ", port=" + mInputPort 199 + "}"; 200 } 201 202 public static class Builder { 203 private Event mEvent; 204 Builder()205 Builder() { 206 mEvent = new Event(); 207 } 208 setId(int id)209 public void setId(int id) { 210 mEvent.mId = id; 211 } 212 setCommand(Command command)213 public void setCommand(Command command) { 214 mEvent.mCommand = command; 215 } 216 setName(String name)217 public void setName(String name) { 218 mEvent.mName = name; 219 } 220 setInjections(int[] events)221 public void setInjections(int[] events) { 222 mEvent.mInjections = events; 223 } 224 setTimestampOffsetMicros(long offsetMicros)225 public void setTimestampOffsetMicros(long offsetMicros) { 226 mEvent.mTimestampOffsetMicros = offsetMicros; 227 } 228 229 /** 230 * Sets the event codes that should be registered with a {@code register} command. 231 * 232 * @param configuration An array of ioctls and event codes, as described at 233 * {@link Event#getConfiguration()}. 234 */ setConfiguration(SparseArray<int[]> configuration)235 public void setConfiguration(SparseArray<int[]> configuration) { 236 mEvent.mConfiguration = configuration; 237 } 238 setVendorId(int vendorId)239 public void setVendorId(int vendorId) { 240 mEvent.mVendorId = vendorId; 241 } 242 setProductId(int productId)243 public void setProductId(int productId) { 244 mEvent.mProductId = productId; 245 } 246 setVersionId(int versionId)247 public void setVersionId(int versionId) { 248 mEvent.mVersionId = versionId; 249 } 250 setBusId(int busId)251 public void setBusId(int busId) { 252 mEvent.mBusId = busId; 253 } 254 setDurationNanos(long durationNanos)255 public void setDurationNanos(long durationNanos) { 256 mEvent.mDurationNanos = durationNanos; 257 } 258 setFfEffectsMax(int ffEffectsMax)259 public void setFfEffectsMax(int ffEffectsMax) { 260 mEvent.mFfEffectsMax = ffEffectsMax; 261 } 262 setAbsInfo(SparseArray<InputAbsInfo> absInfo)263 public void setAbsInfo(SparseArray<InputAbsInfo> absInfo) { 264 mEvent.mAbsInfo = absInfo; 265 } 266 setInputPort(String port)267 public void setInputPort(String port) { 268 mEvent.mInputPort = port; 269 } 270 setSyncToken(String syncToken)271 public void setSyncToken(String syncToken) { 272 mEvent.mSyncToken = Objects.requireNonNull(syncToken, "Sync token must not be null"); 273 } 274 build()275 public Event build() { 276 if (mEvent.mId == -1) { 277 throw new IllegalStateException("No event id"); 278 } else if (mEvent.mCommand == null) { 279 throw new IllegalStateException("Event does not contain a command"); 280 } 281 switch (mEvent.mCommand) { 282 case REGISTER -> { 283 if (mEvent.mConfiguration == null) { 284 throw new IllegalStateException( 285 "Device registration is missing configuration"); 286 } 287 } 288 case DELAY -> { 289 if (mEvent.mDurationNanos <= 0) { 290 throw new IllegalStateException("Delay has missing or invalid duration"); 291 } 292 } 293 case INJECT -> { 294 if (mEvent.mInjections == null) { 295 throw new IllegalStateException("Inject command is missing injection data"); 296 } 297 } 298 case SYNC -> { 299 if (mEvent.mSyncToken == null) { 300 throw new IllegalStateException("Sync command is missing sync token"); 301 } 302 } 303 } 304 return mEvent; 305 } 306 } 307 } 308