1 /* 2 * Copyright (C) 2019 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.os; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.TestApi; 23 import android.media.AudioAttributes; 24 25 import java.lang.annotation.Retention; 26 import java.lang.annotation.RetentionPolicy; 27 import java.util.Objects; 28 29 /** 30 * Encapsulates a collection of attributes describing information about a vibration. 31 */ 32 public final class VibrationAttributes implements Parcelable { 33 private static final String TAG = "VibrationAttributes"; 34 35 /** @hide */ 36 @IntDef(prefix = { "USAGE_CLASS_" }, value = { 37 USAGE_CLASS_UNKNOWN, 38 USAGE_CLASS_ALARM, 39 USAGE_CLASS_FEEDBACK, 40 USAGE_CLASS_MEDIA, 41 }) 42 @Retention(RetentionPolicy.SOURCE) 43 public @interface UsageClass {} 44 45 /** @hide */ 46 @IntDef(prefix = { "USAGE_" }, value = { 47 USAGE_UNKNOWN, 48 USAGE_ACCESSIBILITY, 49 USAGE_ALARM, 50 USAGE_COMMUNICATION_REQUEST, 51 USAGE_HARDWARE_FEEDBACK, 52 USAGE_MEDIA, 53 USAGE_NOTIFICATION, 54 USAGE_PHYSICAL_EMULATION, 55 USAGE_RINGTONE, 56 USAGE_TOUCH, 57 }) 58 @Retention(RetentionPolicy.SOURCE) 59 public @interface Usage {} 60 61 /** 62 * Vibration usage filter value to match all usages. 63 * @hide 64 */ 65 public static final int USAGE_FILTER_MATCH_ALL = -1; 66 /** 67 * Vibration usage class value to use when the vibration usage class is unknown. 68 */ 69 public static final int USAGE_CLASS_UNKNOWN = 0x0; 70 /** 71 * Vibration usage class value to use when the vibration is initiated to catch user's 72 * attention, such as alarm, ringtone, and notification vibrations. 73 */ 74 public static final int USAGE_CLASS_ALARM = 0x1; 75 /** 76 * Vibration usage class value to use when the vibration is initiated as a response to user's 77 * actions, such as emulation of physical effects, and texting feedback vibration. 78 */ 79 public static final int USAGE_CLASS_FEEDBACK = 0x2; 80 /** 81 * Vibration usage class value to use when the vibration is part of media, such as music, movie, 82 * soundtrack, game or animations. 83 */ 84 public static final int USAGE_CLASS_MEDIA = 0x3; 85 86 /** 87 * Mask for vibration usage class value. 88 */ 89 public static final int USAGE_CLASS_MASK = 0xF; 90 91 /** 92 * Usage value to use when usage is unknown. 93 */ 94 public static final int USAGE_UNKNOWN = 0x0 | USAGE_CLASS_UNKNOWN; 95 /** 96 * Usage value to use for alarm vibrations. 97 */ 98 public static final int USAGE_ALARM = 0x10 | USAGE_CLASS_ALARM; 99 /** 100 * Usage value to use for ringtone vibrations. 101 */ 102 public static final int USAGE_RINGTONE = 0x20 | USAGE_CLASS_ALARM; 103 /** 104 * Usage value to use for notification vibrations. 105 */ 106 public static final int USAGE_NOTIFICATION = 0x30 | USAGE_CLASS_ALARM; 107 /** 108 * Usage value to use for vibrations which mean a request to enter/end a 109 * communication with the user, such as a voice prompt. 110 */ 111 public static final int USAGE_COMMUNICATION_REQUEST = 0x40 | USAGE_CLASS_ALARM; 112 /** 113 * Usage value to use for touch vibrations. 114 * 115 * <p>Most typical haptic feedback should be classed as <em>touch</em> feedback. Examples 116 * include vibrations for tap, long press, drag and scroll. 117 */ 118 public static final int USAGE_TOUCH = 0x10 | USAGE_CLASS_FEEDBACK; 119 /** 120 * Usage value to use for vibrations which emulate physical hardware reactions, 121 * such as edge squeeze. 122 * 123 * <p>Note that normal screen-touch feedback "click" effects would typically be 124 * classed as {@link #USAGE_TOUCH}, and that on-screen "physical" animations 125 * like bouncing would be {@link #USAGE_MEDIA}. 126 */ 127 public static final int USAGE_PHYSICAL_EMULATION = 0x20 | USAGE_CLASS_FEEDBACK; 128 /** 129 * Usage value to use for vibrations which provide a feedback for hardware 130 * component interaction, such as a fingerprint sensor. 131 */ 132 public static final int USAGE_HARDWARE_FEEDBACK = 0x30 | USAGE_CLASS_FEEDBACK; 133 /** 134 * Usage value to use for accessibility vibrations, such as with a screen reader. 135 */ 136 public static final int USAGE_ACCESSIBILITY = 0x40 | USAGE_CLASS_FEEDBACK; 137 /** 138 * Usage value to use for media vibrations, such as music, movie, soundtrack, animations, games, 139 * or any interactive media that isn't for touch feedback specifically. 140 */ 141 public static final int USAGE_MEDIA = 0x10 | USAGE_CLASS_MEDIA; 142 143 /** 144 * @hide 145 */ 146 @IntDef(prefix = { "FLAG_" }, flag = true, value = { 147 FLAG_BYPASS_INTERRUPTION_POLICY, 148 FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF 149 }) 150 @Retention(RetentionPolicy.SOURCE) 151 public @interface Flag{} 152 153 /** 154 * Flag requesting vibration effect to be played even under limited interruptions. 155 */ 156 public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1; 157 158 /** 159 * Flag requesting vibration effect to be played even when user settings are disabling it. 160 * 161 * <p>Flag introduced to represent 162 * {@link android.view.HapticFeedbackConstants#FLAG_IGNORE_GLOBAL_SETTING} and 163 * {@link AudioAttributes#FLAG_BYPASS_MUTE}. 164 * 165 * @hide 166 */ 167 public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 0x2; 168 169 /** 170 * Flag requesting vibration effect to be played with fresh user settings values. 171 * 172 * <p>This flag is not protected by any permission, but vibrations that use it require an extra 173 * query of user vibration intensity settings, ringer mode and other controls that affect the 174 * vibration effect playback, which can increase the latency for the overall request. 175 * 176 * <p>This is intended to be used on scenarios where the user settings might have changed 177 * recently, and needs to be applied to this vibration, like settings controllers that preview 178 * newly set intensities to the user. 179 * 180 * @hide 181 */ 182 public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 0x3; 183 184 /** 185 * All flags supported by vibrator service, update it when adding new flag. 186 * @hide 187 */ 188 public static final int FLAG_ALL_SUPPORTED = 189 FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF 190 | FLAG_INVALIDATE_SETTINGS_CACHE; 191 192 /** Creates a new {@link VibrationAttributes} instance with given usage. */ createForUsage(@sage int usage)193 public static @NonNull VibrationAttributes createForUsage(@Usage int usage) { 194 return new VibrationAttributes.Builder().setUsage(usage).build(); 195 } 196 197 private final int mUsage; 198 private final int mFlags; 199 private final int mOriginalAudioUsage; 200 VibrationAttributes(@sage int usage, @AudioAttributes.AttributeUsage int audioUsage, @Flag int flags)201 private VibrationAttributes(@Usage int usage, @AudioAttributes.AttributeUsage int audioUsage, 202 @Flag int flags) { 203 mUsage = usage; 204 mOriginalAudioUsage = audioUsage; 205 mFlags = flags & FLAG_ALL_SUPPORTED; 206 } 207 208 /** 209 * Return the vibration usage class. 210 */ 211 @UsageClass getUsageClass()212 public int getUsageClass() { 213 return mUsage & USAGE_CLASS_MASK; 214 } 215 216 /** 217 * Return the vibration usage. 218 */ 219 @Usage getUsage()220 public int getUsage() { 221 return mUsage; 222 } 223 224 /** 225 * Return the flags. 226 * @return a combined mask of all flags 227 */ 228 @Flag getFlags()229 public int getFlags() { 230 return mFlags; 231 } 232 233 /** 234 * Check whether a flag is set 235 * @return true if a flag is set and false otherwise 236 */ isFlagSet(@lag int flag)237 public boolean isFlagSet(@Flag int flag) { 238 return (mFlags & flag) > 0; 239 } 240 241 /** 242 * Return {@link AudioAttributes} usage equivalent to {@link #getUsage()}. 243 * @return one of {@link AudioAttributes#SDK_USAGES} that represents {@link #getUsage()} 244 * @hide 245 */ 246 @TestApi 247 @AudioAttributes.AttributeUsage getAudioUsage()248 public int getAudioUsage() { 249 if (mOriginalAudioUsage != AudioAttributes.USAGE_UNKNOWN) { 250 // Return same audio usage set in the Builder. 251 return mOriginalAudioUsage; 252 } 253 // Return correct audio usage based on the vibration usage set in the Builder. 254 switch (mUsage) { 255 case USAGE_NOTIFICATION: 256 return AudioAttributes.USAGE_NOTIFICATION; 257 case USAGE_COMMUNICATION_REQUEST: 258 return AudioAttributes.USAGE_VOICE_COMMUNICATION; 259 case USAGE_RINGTONE: 260 return AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 261 case USAGE_TOUCH: 262 return AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; 263 case USAGE_ALARM: 264 return AudioAttributes.USAGE_ALARM; 265 case USAGE_ACCESSIBILITY: 266 return AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY; 267 case USAGE_MEDIA: 268 return AudioAttributes.USAGE_MEDIA; 269 default: 270 return AudioAttributes.USAGE_UNKNOWN; 271 } 272 } 273 274 @Override describeContents()275 public int describeContents() { 276 return 0; 277 } 278 279 @Override writeToParcel(@onNull Parcel dest, int flags)280 public void writeToParcel(@NonNull Parcel dest, int flags) { 281 dest.writeInt(mUsage); 282 dest.writeInt(mOriginalAudioUsage); 283 dest.writeInt(mFlags); 284 } 285 VibrationAttributes(Parcel src)286 private VibrationAttributes(Parcel src) { 287 mUsage = src.readInt(); 288 mOriginalAudioUsage = src.readInt(); 289 mFlags = src.readInt(); 290 } 291 292 public static final @NonNull Parcelable.Creator<VibrationAttributes> 293 CREATOR = new Parcelable.Creator<VibrationAttributes>() { 294 public VibrationAttributes createFromParcel(Parcel p) { 295 return new VibrationAttributes(p); 296 } 297 public VibrationAttributes[] newArray(int size) { 298 return new VibrationAttributes[size]; 299 } 300 }; 301 302 @Override equals(@ullable Object o)303 public boolean equals(@Nullable Object o) { 304 if (this == o) { 305 return true; 306 } 307 if (o == null || getClass() != o.getClass()) { 308 return false; 309 } 310 VibrationAttributes rhs = (VibrationAttributes) o; 311 return mUsage == rhs.mUsage && mOriginalAudioUsage == rhs.mOriginalAudioUsage 312 && mFlags == rhs.mFlags; 313 } 314 315 @Override hashCode()316 public int hashCode() { 317 return Objects.hash(mUsage, mOriginalAudioUsage, mFlags); 318 } 319 320 @Override toString()321 public String toString() { 322 return "VibrationAttributes:" 323 + " Usage=" + usageToString() 324 + " Audio Usage= " + AudioAttributes.usageToString(mOriginalAudioUsage) 325 + " Flags=" + mFlags; 326 } 327 328 /** @hide */ usageToString()329 public String usageToString() { 330 return usageToString(mUsage); 331 } 332 333 /** @hide */ usageToString(@sage int usage)334 public static String usageToString(@Usage int usage) { 335 switch (usage) { 336 case USAGE_UNKNOWN: 337 return "UNKNOWN"; 338 case USAGE_ALARM: 339 return "ALARM"; 340 case USAGE_ACCESSIBILITY: 341 return "ACCESSIBILITY"; 342 case USAGE_RINGTONE: 343 return "RINGTONE"; 344 case USAGE_NOTIFICATION: 345 return "NOTIFICATION"; 346 case USAGE_COMMUNICATION_REQUEST: 347 return "COMMUNICATION_REQUEST"; 348 case USAGE_MEDIA: 349 return "MEDIA"; 350 case USAGE_TOUCH: 351 return "TOUCH"; 352 case USAGE_PHYSICAL_EMULATION: 353 return "PHYSICAL_EMULATION"; 354 case USAGE_HARDWARE_FEEDBACK: 355 return "HARDWARE_FEEDBACK"; 356 default: 357 return "unknown usage " + usage; 358 } 359 } 360 361 /** 362 * Builder class for {@link VibrationAttributes} objects. 363 * By default, all information is set to UNKNOWN. 364 */ 365 public static final class Builder { 366 private int mUsage = USAGE_UNKNOWN; 367 private int mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN; 368 private int mFlags = 0x0; 369 370 /** 371 * Constructs a new Builder with the defaults. 372 */ Builder()373 public Builder() { 374 } 375 376 /** 377 * Constructs a new Builder from a given VibrationAttributes. 378 */ Builder(@ullable VibrationAttributes vib)379 public Builder(@Nullable VibrationAttributes vib) { 380 if (vib != null) { 381 mUsage = vib.mUsage; 382 mOriginalAudioUsage = vib.mOriginalAudioUsage; 383 mFlags = vib.mFlags; 384 } 385 } 386 387 /** 388 * Constructs a new Builder from AudioAttributes. 389 */ Builder(@onNull AudioAttributes audio)390 public Builder(@NonNull AudioAttributes audio) { 391 setUsage(audio); 392 setFlags(audio); 393 } 394 setUsage(@onNull AudioAttributes audio)395 private void setUsage(@NonNull AudioAttributes audio) { 396 mOriginalAudioUsage = audio.getUsage(); 397 switch (audio.getUsage()) { 398 case AudioAttributes.USAGE_NOTIFICATION: 399 case AudioAttributes.USAGE_NOTIFICATION_EVENT: 400 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 401 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 402 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 403 mUsage = USAGE_NOTIFICATION; 404 break; 405 case AudioAttributes.USAGE_VOICE_COMMUNICATION: 406 case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING: 407 case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: 408 case AudioAttributes.USAGE_ASSISTANT: 409 mUsage = USAGE_COMMUNICATION_REQUEST; 410 break; 411 case AudioAttributes.USAGE_NOTIFICATION_RINGTONE: 412 mUsage = USAGE_RINGTONE; 413 break; 414 case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY: 415 mUsage = USAGE_ACCESSIBILITY; 416 break; 417 case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION: 418 mUsage = USAGE_TOUCH; 419 break; 420 case AudioAttributes.USAGE_ALARM: 421 mUsage = USAGE_ALARM; 422 break; 423 case AudioAttributes.USAGE_MEDIA: 424 case AudioAttributes.USAGE_GAME: 425 mUsage = USAGE_MEDIA; 426 break; 427 default: 428 mUsage = USAGE_UNKNOWN; 429 } 430 } 431 setFlags(@onNull AudioAttributes audio)432 private void setFlags(@NonNull AudioAttributes audio) { 433 if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { 434 mFlags |= FLAG_BYPASS_INTERRUPTION_POLICY; 435 } 436 if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_MUTE) != 0) { 437 // Muted audio stream translates to vibration usage having the value 438 // Vibrator.VIBRATION_INTENSITY_OFF set in the user setting. 439 mFlags |= FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; 440 } 441 } 442 443 /** 444 * Combines all of the attributes that have been set and returns a new 445 * {@link VibrationAttributes} object. 446 * @return a new {@link VibrationAttributes} object 447 */ build()448 public @NonNull VibrationAttributes build() { 449 VibrationAttributes ans = new VibrationAttributes(mUsage, mOriginalAudioUsage, mFlags); 450 return ans; 451 } 452 453 /** 454 * Sets the attribute describing the type of the corresponding vibration. 455 * @param usage The type of usage for the vibration 456 * @return the same Builder instance. 457 */ setUsage(@sage int usage)458 public @NonNull Builder setUsage(@Usage int usage) { 459 mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN; 460 mUsage = usage; 461 return this; 462 } 463 464 /** 465 * Sets only the flags specified in the bitmask, leaving the other supported flag values 466 * unchanged in the builder. 467 * 468 * @param flags Combination of flags to be set. 469 * @param mask Bit range that should be changed. 470 * @return the same Builder instance. 471 */ setFlags(@lag int flags, int mask)472 public @NonNull Builder setFlags(@Flag int flags, int mask) { 473 mask &= FLAG_ALL_SUPPORTED; 474 mFlags = (mFlags & ~mask) | (flags & mask); 475 return this; 476 } 477 478 /** 479 * Set all supported flags with given combination of flags, overriding any previous values 480 * set to this builder. 481 * 482 * @param flags combination of flags to be set. 483 * @return the same Builder instance. 484 * 485 * @hide 486 */ setFlags(@lag int flags)487 public @NonNull Builder setFlags(@Flag int flags) { 488 return setFlags(flags, FLAG_ALL_SUPPORTED); 489 } 490 } 491 } 492