1 /* 2 * Copyright (C) 2021 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.FloatRange; 20 import android.annotation.IntDef; 21 import android.annotation.IntRange; 22 import android.annotation.NonNull; 23 import android.annotation.SystemApi; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.os.SystemClock; 27 import android.view.InputEvent; 28 import android.view.MotionEvent; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 33 /** 34 * An event describing a touchscreen interaction originating from a remote device. 35 * 36 * The pointer id, tool type, action, and location are required; pressure and main axis size are 37 * optional. 38 * 39 * Note: A VirtualTouchEvent with ACTION_CANCEL can only be created with TOOL_TYPE_PALM (and vice 40 * versa). Events are injected into the uinput kernel module, which has no concept of cancelling 41 * an action. The only way to state the intention that a pointer should not be handled as a pointer 42 * is to change its tool type to TOOL_TYPE_PALM. 43 * 44 * @hide 45 */ 46 @SystemApi 47 public final class VirtualTouchEvent implements Parcelable { 48 49 /** @hide */ 50 public static final int TOOL_TYPE_UNKNOWN = MotionEvent.TOOL_TYPE_UNKNOWN; 51 /** Tool type indicating that the user's finger is the origin of the event. */ 52 public static final int TOOL_TYPE_FINGER = MotionEvent.TOOL_TYPE_FINGER; 53 /** 54 * Tool type indicating that a user's palm (or other input mechanism to be rejected) is the 55 * origin of the event. 56 */ 57 public static final int TOOL_TYPE_PALM = MotionEvent.TOOL_TYPE_PALM; 58 /** @hide */ 59 @IntDef(prefix = { "TOOL_TYPE_" }, value = { 60 TOOL_TYPE_UNKNOWN, 61 TOOL_TYPE_FINGER, 62 TOOL_TYPE_PALM, 63 }) 64 @Retention(RetentionPolicy.SOURCE) 65 public @interface ToolType {} 66 67 /** @hide */ 68 public static final int ACTION_UNKNOWN = -1; 69 /** Action indicating the tool has been pressed down to the touchscreen. */ 70 public static final int ACTION_DOWN = MotionEvent.ACTION_DOWN; 71 /** Action indicating the tool has been lifted from the touchscreen. */ 72 public static final int ACTION_UP = MotionEvent.ACTION_UP; 73 /** Action indicating the tool has been moved along the face of the touchscreen. */ 74 public static final int ACTION_MOVE = MotionEvent.ACTION_MOVE; 75 /** Action indicating the tool cancelled the current movement. */ 76 public static final int ACTION_CANCEL = MotionEvent.ACTION_CANCEL; 77 /** @hide */ 78 @IntDef(prefix = { "ACTION_" }, value = { 79 ACTION_UNKNOWN, 80 ACTION_DOWN, 81 ACTION_UP, 82 ACTION_MOVE, 83 ACTION_CANCEL, 84 }) 85 @Retention(RetentionPolicy.SOURCE) 86 public @interface Action {} 87 88 // The maximum number of pointers that can be touching the screen at once. (See MAX_POINTERS 89 // in frameworks/native/include/input/Input.h) 90 private static final int MAX_POINTERS = 16; 91 92 private final int mPointerId; 93 private final @ToolType int mToolType; 94 private final @Action int mAction; 95 private final float mX; 96 private final float mY; 97 private final float mPressure; 98 private final float mMajorAxisSize; 99 private final long mEventTimeNanos; 100 VirtualTouchEvent(int pointerId, @ToolType int toolType, @Action int action, float x, float y, float pressure, float majorAxisSize, long eventTimeNanos)101 private VirtualTouchEvent(int pointerId, @ToolType int toolType, @Action int action, 102 float x, float y, float pressure, float majorAxisSize, long eventTimeNanos) { 103 mPointerId = pointerId; 104 mToolType = toolType; 105 mAction = action; 106 mX = x; 107 mY = y; 108 mPressure = pressure; 109 mMajorAxisSize = majorAxisSize; 110 mEventTimeNanos = eventTimeNanos; 111 } 112 VirtualTouchEvent(@onNull Parcel parcel)113 private VirtualTouchEvent(@NonNull Parcel parcel) { 114 mPointerId = parcel.readInt(); 115 mToolType = parcel.readInt(); 116 mAction = parcel.readInt(); 117 mX = parcel.readFloat(); 118 mY = parcel.readFloat(); 119 mPressure = parcel.readFloat(); 120 mMajorAxisSize = parcel.readFloat(); 121 mEventTimeNanos = parcel.readLong(); 122 } 123 124 @Override writeToParcel(@onNull Parcel dest, int flags)125 public void writeToParcel(@NonNull Parcel dest, int flags) { 126 dest.writeInt(mPointerId); 127 dest.writeInt(mToolType); 128 dest.writeInt(mAction); 129 dest.writeFloat(mX); 130 dest.writeFloat(mY); 131 dest.writeFloat(mPressure); 132 dest.writeFloat(mMajorAxisSize); 133 dest.writeLong(mEventTimeNanos); 134 } 135 136 @Override describeContents()137 public int describeContents() { 138 return 0; 139 } 140 141 /** 142 * Returns the pointer id associated with this event. 143 */ getPointerId()144 public int getPointerId() { 145 return mPointerId; 146 } 147 148 /** 149 * Returns the tool type associated with this event. 150 */ getToolType()151 public @ToolType int getToolType() { 152 return mToolType; 153 } 154 155 /** 156 * Returns the action associated with this event. 157 */ getAction()158 public @Action int getAction() { 159 return mAction; 160 } 161 162 /** 163 * Returns the x-axis location associated with this event. 164 */ getX()165 public float getX() { 166 return mX; 167 } 168 169 /** 170 * Returns the y-axis location associated with this event. 171 */ getY()172 public float getY() { 173 return mY; 174 } 175 176 /** 177 * Returns the pressure associated with this event. Returns {@link Float#NaN} if omitted. 178 */ getPressure()179 public float getPressure() { 180 return mPressure; 181 } 182 183 /** 184 * Returns the major axis size associated with this event. Returns {@link Float#NaN} if omitted. 185 */ getMajorAxisSize()186 public float getMajorAxisSize() { 187 return mMajorAxisSize; 188 } 189 190 /** 191 * Returns the time this event occurred, in the {@link SystemClock#uptimeMillis()} time base but 192 * with nanosecond (instead of millisecond) precision. 193 * 194 * @see InputEvent#getEventTime() 195 */ getEventTimeNanos()196 public long getEventTimeNanos() { 197 return mEventTimeNanos; 198 } 199 200 /** 201 * Builder for {@link VirtualTouchEvent}. 202 */ 203 public static final class Builder { 204 205 private @ToolType int mToolType = TOOL_TYPE_UNKNOWN; 206 private int mPointerId = MotionEvent.INVALID_POINTER_ID; 207 private @Action int mAction = ACTION_UNKNOWN; 208 private float mX = Float.NaN; 209 private float mY = Float.NaN; 210 private float mPressure = Float.NaN; 211 private float mMajorAxisSize = Float.NaN; 212 private long mEventTimeNanos = 0L; 213 214 /** 215 * Creates a {@link VirtualTouchEvent} object with the current builder configuration. 216 * 217 * @throws IllegalArgumentException if one of the required arguments is missing or if 218 * ACTION_CANCEL is not set in combination with TOOL_TYPE_PALM. See 219 * {@link VirtualTouchEvent} for a detailed explanation. 220 */ build()221 public @NonNull VirtualTouchEvent build() { 222 if (mToolType == TOOL_TYPE_UNKNOWN || mPointerId == MotionEvent.INVALID_POINTER_ID 223 || mAction == ACTION_UNKNOWN || Float.isNaN(mX) || Float.isNaN(mY)) { 224 throw new IllegalArgumentException( 225 "Cannot build virtual touch event with unset required fields"); 226 } 227 if ((mToolType == TOOL_TYPE_PALM && mAction != ACTION_CANCEL) 228 || (mAction == ACTION_CANCEL && mToolType != TOOL_TYPE_PALM)) { 229 throw new IllegalArgumentException( 230 "ACTION_CANCEL and TOOL_TYPE_PALM must always appear together"); 231 } 232 return new VirtualTouchEvent(mPointerId, mToolType, mAction, mX, mY, mPressure, 233 mMajorAxisSize, mEventTimeNanos); 234 } 235 236 /** 237 * Sets the pointer id of the event. 238 * 239 * <p>A Valid pointer id need to be in the range of 0 to 15. 240 * 241 * @return this builder, to allow for chaining of calls 242 */ setPointerId( @ntRangefrom = 0, to = MAX_POINTERS - 1) int pointerId)243 public @NonNull Builder setPointerId( 244 @IntRange(from = 0, to = MAX_POINTERS - 1) int pointerId) { 245 if (pointerId < 0 || pointerId > 15) { 246 throw new IllegalArgumentException( 247 "The pointer id must be in the range 0 - " + (MAX_POINTERS - 1) 248 + "inclusive, but was: " + pointerId); 249 } 250 mPointerId = pointerId; 251 return this; 252 } 253 254 /** 255 * Sets the tool type of the event. 256 * 257 * @return this builder, to allow for chaining of calls 258 */ setToolType(@oolType int toolType)259 public @NonNull Builder setToolType(@ToolType int toolType) { 260 if (toolType != TOOL_TYPE_FINGER && toolType != TOOL_TYPE_PALM) { 261 throw new IllegalArgumentException("Unsupported touch event tool type"); 262 } 263 mToolType = toolType; 264 return this; 265 } 266 267 /** 268 * Sets the action of the event. 269 * 270 * @return this builder, to allow for chaining of calls 271 */ setAction(@ction int action)272 public @NonNull Builder setAction(@Action int action) { 273 if (action != ACTION_DOWN && action != ACTION_UP && action != ACTION_MOVE 274 && action != ACTION_CANCEL) { 275 throw new IllegalArgumentException("Unsupported touch event action type"); 276 } 277 mAction = action; 278 return this; 279 } 280 281 /** 282 * Sets the x-axis location of the event. 283 * 284 * @return this builder, to allow for chaining of calls 285 */ setX(float absX)286 public @NonNull Builder setX(float absX) { 287 mX = absX; 288 return this; 289 } 290 291 /** 292 * Sets the y-axis location of the event. 293 * 294 * @return this builder, to allow for chaining of calls 295 */ setY(float absY)296 public @NonNull Builder setY(float absY) { 297 mY = absY; 298 return this; 299 } 300 301 /** 302 * Sets the pressure of the event. This field is optional and can be omitted. 303 * 304 * @param pressure The pressure of the touch. 305 * Note: The VirtualTouchscreen, consuming VirtualTouchEvents, is 306 * configured with a pressure axis range from 0.0 to 255.0. Only the 307 * lower end of the range is enforced. You can pass values larger than 308 * 255.0. With physical input devices this could happen if the 309 * calibration is off. Values larger than 255.0 will not be trimmed and 310 * passed on as is. 311 * 312 * @throws IllegalArgumentException if the pressure is smaller than 0. 313 * 314 * @return this builder, to allow for chaining of calls 315 */ setPressure(@loatRangefrom = 0f) float pressure)316 public @NonNull Builder setPressure(@FloatRange(from = 0f) float pressure) { 317 if (pressure < 0f) { 318 throw new IllegalArgumentException("Touch event pressure cannot be negative"); 319 } 320 mPressure = pressure; 321 return this; 322 } 323 324 /** 325 * Sets the major axis size of the event. This field is optional and can be omitted. 326 * 327 * @return this builder, to allow for chaining of calls 328 */ setMajorAxisSize(@loatRangefrom = 0f) float majorAxisSize)329 public @NonNull Builder setMajorAxisSize(@FloatRange(from = 0f) float majorAxisSize) { 330 if (majorAxisSize < 0f) { 331 throw new IllegalArgumentException( 332 "Touch event major axis size cannot be negative"); 333 } 334 mMajorAxisSize = majorAxisSize; 335 return this; 336 } 337 338 /** 339 * Sets the time (in nanoseconds) when this specific event was generated. This may be 340 * obtained from {@link SystemClock#uptimeMillis()} (with nanosecond precision instead of 341 * millisecond), but can be different depending on the use case. 342 * This field is optional and can be omitted. 343 * 344 * @return this builder, to allow for chaining of calls 345 * @see InputEvent#getEventTime() 346 */ setEventTimeNanos(long eventTimeNanos)347 public @NonNull Builder setEventTimeNanos(long eventTimeNanos) { 348 if (eventTimeNanos < 0L) { 349 throw new IllegalArgumentException("Event time cannot be negative"); 350 } 351 mEventTimeNanos = eventTimeNanos; 352 return this; 353 } 354 } 355 356 public static final @NonNull Parcelable.Creator<VirtualTouchEvent> CREATOR = 357 new Parcelable.Creator<VirtualTouchEvent>() { 358 public VirtualTouchEvent createFromParcel(Parcel source) { 359 return new VirtualTouchEvent(source); 360 } 361 public VirtualTouchEvent[] newArray(int size) { 362 return new VirtualTouchEvent[size]; 363 } 364 }; 365 } 366