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.NonNull; 22 import android.annotation.SystemApi; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.view.MotionEvent; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 30 /** 31 * An event describing a touchscreen interaction originating from a remote device. 32 * 33 * The pointer id, tool type, action, and location are required; pressure and main axis size are 34 * optional. 35 * 36 * @hide 37 */ 38 @SystemApi 39 public final class VirtualTouchEvent implements Parcelable { 40 41 /** @hide */ 42 public static final int TOOL_TYPE_UNKNOWN = MotionEvent.TOOL_TYPE_UNKNOWN; 43 /** Tool type indicating that the user's finger is the origin of the event. */ 44 public static final int TOOL_TYPE_FINGER = MotionEvent.TOOL_TYPE_FINGER; 45 /** 46 * Tool type indicating that a user's palm (or other input mechanism to be rejected) is the 47 * origin of the event. 48 */ 49 public static final int TOOL_TYPE_PALM = MotionEvent.TOOL_TYPE_PALM; 50 /** @hide */ 51 @IntDef(prefix = { "TOOL_TYPE_" }, value = { 52 TOOL_TYPE_UNKNOWN, 53 TOOL_TYPE_FINGER, 54 TOOL_TYPE_PALM, 55 }) 56 @Retention(RetentionPolicy.SOURCE) 57 public @interface ToolType {} 58 59 /** @hide */ 60 public static final int ACTION_UNKNOWN = -1; 61 /** Action indicating the tool has been pressed down to the touchscreen. */ 62 public static final int ACTION_DOWN = MotionEvent.ACTION_DOWN; 63 /** Action indicating the tool has been lifted from the touchscreen. */ 64 public static final int ACTION_UP = MotionEvent.ACTION_UP; 65 /** Action indicating the tool has been moved along the face of the touchscreen. */ 66 public static final int ACTION_MOVE = MotionEvent.ACTION_MOVE; 67 /** Action indicating the tool cancelled the current movement. */ 68 public static final int ACTION_CANCEL = MotionEvent.ACTION_CANCEL; 69 /** @hide */ 70 @IntDef(prefix = { "ACTION_" }, value = { 71 ACTION_UNKNOWN, 72 ACTION_DOWN, 73 ACTION_UP, 74 ACTION_MOVE, 75 ACTION_CANCEL, 76 }) 77 @Retention(RetentionPolicy.SOURCE) 78 public @interface Action {} 79 80 private final int mPointerId; 81 private final @ToolType int mToolType; 82 private final @Action int mAction; 83 private final float mX; 84 private final float mY; 85 private final float mPressure; 86 private final float mMajorAxisSize; 87 VirtualTouchEvent(int pointerId, @ToolType int toolType, @Action int action, float x, float y, float pressure, float majorAxisSize)88 private VirtualTouchEvent(int pointerId, @ToolType int toolType, @Action int action, 89 float x, float y, float pressure, float majorAxisSize) { 90 mPointerId = pointerId; 91 mToolType = toolType; 92 mAction = action; 93 mX = x; 94 mY = y; 95 mPressure = pressure; 96 mMajorAxisSize = majorAxisSize; 97 } 98 VirtualTouchEvent(@onNull Parcel parcel)99 private VirtualTouchEvent(@NonNull Parcel parcel) { 100 mPointerId = parcel.readInt(); 101 mToolType = parcel.readInt(); 102 mAction = parcel.readInt(); 103 mX = parcel.readFloat(); 104 mY = parcel.readFloat(); 105 mPressure = parcel.readFloat(); 106 mMajorAxisSize = parcel.readFloat(); 107 } 108 109 @Override writeToParcel(@onNull Parcel dest, int flags)110 public void writeToParcel(@NonNull Parcel dest, int flags) { 111 dest.writeInt(mPointerId); 112 dest.writeInt(mToolType); 113 dest.writeInt(mAction); 114 dest.writeFloat(mX); 115 dest.writeFloat(mY); 116 dest.writeFloat(mPressure); 117 dest.writeFloat(mMajorAxisSize); 118 } 119 120 @Override describeContents()121 public int describeContents() { 122 return 0; 123 } 124 125 /** 126 * Returns the pointer id associated with this event. 127 */ getPointerId()128 public int getPointerId() { 129 return mPointerId; 130 } 131 132 /** 133 * Returns the tool type associated with this event. 134 */ getToolType()135 public @ToolType int getToolType() { 136 return mToolType; 137 } 138 139 /** 140 * Returns the action associated with this event. 141 */ getAction()142 public @Action int getAction() { 143 return mAction; 144 } 145 146 /** 147 * Returns the x-axis location associated with this event. 148 */ getX()149 public float getX() { 150 return mX; 151 } 152 153 /** 154 * Returns the y-axis location associated with this event. 155 */ getY()156 public float getY() { 157 return mY; 158 } 159 160 /** 161 * Returns the pressure associated with this event. Returns {@link Float#NaN} if omitted. 162 */ getPressure()163 public float getPressure() { 164 return mPressure; 165 } 166 167 /** 168 * Returns the major axis size associated with this event. Returns {@link Float#NaN} if omitted. 169 */ getMajorAxisSize()170 public float getMajorAxisSize() { 171 return mMajorAxisSize; 172 } 173 174 /** 175 * Builder for {@link VirtualTouchEvent}. 176 */ 177 public static final class Builder { 178 179 private @ToolType int mToolType = TOOL_TYPE_UNKNOWN; 180 private int mPointerId = MotionEvent.INVALID_POINTER_ID; 181 private @Action int mAction = ACTION_UNKNOWN; 182 private float mX = Float.NaN; 183 private float mY = Float.NaN; 184 private float mPressure = Float.NaN; 185 private float mMajorAxisSize = Float.NaN; 186 187 /** 188 * Creates a {@link VirtualTouchEvent} object with the current builder configuration. 189 */ build()190 public @NonNull VirtualTouchEvent build() { 191 if (mToolType == TOOL_TYPE_UNKNOWN || mPointerId == MotionEvent.INVALID_POINTER_ID 192 || mAction == ACTION_UNKNOWN || Float.isNaN(mX) || Float.isNaN(mY)) { 193 throw new IllegalArgumentException( 194 "Cannot build virtual touch event with unset required fields"); 195 } 196 if ((mToolType == TOOL_TYPE_PALM && mAction != ACTION_CANCEL) 197 || (mAction == ACTION_CANCEL && mToolType != TOOL_TYPE_PALM)) { 198 throw new IllegalArgumentException( 199 "ACTION_CANCEL and TOOL_TYPE_PALM must always appear together"); 200 } 201 return new VirtualTouchEvent(mPointerId, mToolType, mAction, mX, mY, mPressure, 202 mMajorAxisSize); 203 } 204 205 /** 206 * Sets the pointer id of the event. 207 * 208 * @return this builder, to allow for chaining of calls 209 */ setPointerId(int pointerId)210 public @NonNull Builder setPointerId(int pointerId) { 211 mPointerId = pointerId; 212 return this; 213 } 214 215 /** 216 * Sets the tool type of the event. 217 * 218 * @return this builder, to allow for chaining of calls 219 */ setToolType(@oolType int toolType)220 public @NonNull Builder setToolType(@ToolType int toolType) { 221 if (toolType != TOOL_TYPE_FINGER && toolType != TOOL_TYPE_PALM) { 222 throw new IllegalArgumentException("Unsupported touch event tool type"); 223 } 224 mToolType = toolType; 225 return this; 226 } 227 228 /** 229 * Sets the action of the event. 230 * 231 * @return this builder, to allow for chaining of calls 232 */ setAction(@ction int action)233 public @NonNull Builder setAction(@Action int action) { 234 if (action != ACTION_DOWN && action != ACTION_UP && action != ACTION_MOVE 235 && action != ACTION_CANCEL) { 236 throw new IllegalArgumentException("Unsupported touch event action type"); 237 } 238 mAction = action; 239 return this; 240 } 241 242 /** 243 * Sets the x-axis location of the event. 244 * 245 * @return this builder, to allow for chaining of calls 246 */ setX(float absX)247 public @NonNull Builder setX(float absX) { 248 mX = absX; 249 return this; 250 } 251 252 /** 253 * Sets the y-axis location of the event. 254 * 255 * @return this builder, to allow for chaining of calls 256 */ setY(float absY)257 public @NonNull Builder setY(float absY) { 258 mY = absY; 259 return this; 260 } 261 262 /** 263 * Sets the pressure of the event. This field is optional and can be omitted. 264 * 265 * @return this builder, to allow for chaining of calls 266 */ setPressure(@loatRangefrom = 0f) float pressure)267 public @NonNull Builder setPressure(@FloatRange(from = 0f) float pressure) { 268 if (pressure < 0f) { 269 throw new IllegalArgumentException("Touch event pressure cannot be negative"); 270 } 271 mPressure = pressure; 272 return this; 273 } 274 275 /** 276 * Sets the major axis size of the event. This field is optional and can be omitted. 277 * 278 * @return this builder, to allow for chaining of calls 279 */ setMajorAxisSize(@loatRangefrom = 0f) float majorAxisSize)280 public @NonNull Builder setMajorAxisSize(@FloatRange(from = 0f) float majorAxisSize) { 281 if (majorAxisSize < 0f) { 282 throw new IllegalArgumentException( 283 "Touch event major axis size cannot be negative"); 284 } 285 mMajorAxisSize = majorAxisSize; 286 return this; 287 } 288 } 289 290 public static final @NonNull Parcelable.Creator<VirtualTouchEvent> CREATOR = 291 new Parcelable.Creator<VirtualTouchEvent>() { 292 public VirtualTouchEvent createFromParcel(Parcel source) { 293 return new VirtualTouchEvent(source); 294 } 295 public VirtualTouchEvent[] newArray(int size) { 296 return new VirtualTouchEvent[size]; 297 } 298 }; 299 } 300