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 @android.ravenwood.annotation.RavenwoodKeepWholeClass 33 public final class VibrationAttributes implements Parcelable { 34 private static final String TAG = "VibrationAttributes"; 35 36 /** @hide */ 37 @IntDef(prefix = { "USAGE_CLASS_" }, value = { 38 USAGE_CLASS_UNKNOWN, 39 USAGE_CLASS_ALARM, 40 USAGE_CLASS_FEEDBACK, 41 USAGE_CLASS_MEDIA, 42 }) 43 @Retention(RetentionPolicy.SOURCE) 44 public @interface UsageClass {} 45 46 /** @hide */ 47 @IntDef(prefix = { "USAGE_" }, value = { 48 USAGE_UNKNOWN, 49 USAGE_ACCESSIBILITY, 50 USAGE_ALARM, 51 USAGE_COMMUNICATION_REQUEST, 52 USAGE_HARDWARE_FEEDBACK, 53 USAGE_MEDIA, 54 USAGE_NOTIFICATION, 55 USAGE_PHYSICAL_EMULATION, 56 USAGE_RINGTONE, 57 USAGE_TOUCH, 58 }) 59 @Retention(RetentionPolicy.SOURCE) 60 public @interface Usage {} 61 62 /** 63 * Vibration usage filter value to match all usages. 64 * @hide 65 */ 66 public static final int USAGE_FILTER_MATCH_ALL = -1; 67 /** 68 * Vibration usage class value to use when the vibration usage class is unknown. 69 */ 70 public static final int USAGE_CLASS_UNKNOWN = 0x0; 71 /** 72 * Vibration usage class value to use when the vibration is initiated to catch user's 73 * attention, such as alarm, ringtone, and notification vibrations. 74 */ 75 public static final int USAGE_CLASS_ALARM = 0x1; 76 /** 77 * Vibration usage class value to use when the vibration is initiated as a response to user's 78 * actions, such as emulation of physical effects, and texting feedback vibration. 79 */ 80 public static final int USAGE_CLASS_FEEDBACK = 0x2; 81 /** 82 * Vibration usage class value to use when the vibration is part of media, such as music, movie, 83 * soundtrack, game or animations. 84 */ 85 public static final int USAGE_CLASS_MEDIA = 0x3; 86 87 /** 88 * Mask for vibration usage class value. 89 */ 90 public static final int USAGE_CLASS_MASK = 0xF; 91 92 /** 93 * Usage value to use when usage is unknown. 94 */ 95 public static final int USAGE_UNKNOWN = 0x0 | USAGE_CLASS_UNKNOWN; 96 /** 97 * Usage value to use for alarm vibrations. 98 */ 99 public static final int USAGE_ALARM = 0x10 | USAGE_CLASS_ALARM; 100 /** 101 * Usage value to use for ringtone vibrations. 102 */ 103 public static final int USAGE_RINGTONE = 0x20 | USAGE_CLASS_ALARM; 104 /** 105 * Usage value to use for notification vibrations. 106 */ 107 public static final int USAGE_NOTIFICATION = 0x30 | USAGE_CLASS_ALARM; 108 /** 109 * Usage value to use for vibrations which mean a request to enter/end a 110 * communication with the user, such as a voice prompt. 111 */ 112 public static final int USAGE_COMMUNICATION_REQUEST = 0x40 | USAGE_CLASS_ALARM; 113 /** 114 * Usage value to use for touch vibrations. 115 * 116 * <p>Most typical haptic feedback should be classed as <em>touch</em> feedback. Examples 117 * include vibrations for tap, long press, drag and scroll. 118 */ 119 public static final int USAGE_TOUCH = 0x10 | USAGE_CLASS_FEEDBACK; 120 /** 121 * Usage value to use for vibrations which emulate physical hardware reactions, 122 * such as edge squeeze. 123 * 124 * <p>Note that normal screen-touch feedback "click" effects would typically be 125 * classed as {@link #USAGE_TOUCH}, and that on-screen "physical" animations 126 * like bouncing would be {@link #USAGE_MEDIA}. 127 */ 128 public static final int USAGE_PHYSICAL_EMULATION = 0x20 | USAGE_CLASS_FEEDBACK; 129 /** 130 * Usage value to use for vibrations which provide a feedback for hardware 131 * component interaction, such as a fingerprint sensor. 132 */ 133 public static final int USAGE_HARDWARE_FEEDBACK = 0x30 | USAGE_CLASS_FEEDBACK; 134 /** 135 * Usage value to use for accessibility vibrations, such as with a screen reader. 136 */ 137 public static final int USAGE_ACCESSIBILITY = 0x40 | USAGE_CLASS_FEEDBACK; 138 /** 139 * Usage value to use for media vibrations, such as music, movie, soundtrack, animations, games, 140 * or any interactive media that isn't for touch feedback specifically. 141 */ 142 public static final int USAGE_MEDIA = 0x10 | USAGE_CLASS_MEDIA; 143 144 /** @hide */ 145 @IntDef(prefix = { "CATEGORY_" }, value = { 146 CATEGORY_UNKNOWN, 147 CATEGORY_KEYBOARD, 148 }) 149 @Retention(RetentionPolicy.SOURCE) 150 public @interface Category {} 151 152 /** 153 * Category value when the vibration category is unknown. 154 * 155 * @hide 156 */ 157 public static final int CATEGORY_UNKNOWN = 0x0; 158 159 /** 160 * Category value for keyboard vibrations. 161 * 162 * <p>Most typical keyboard vibrations are haptic feedback for virtual keyboard key 163 * press/release, for example. 164 * 165 * @hide 166 */ 167 public static final int CATEGORY_KEYBOARD = 1; 168 169 /** 170 * @hide 171 */ 172 @IntDef(prefix = { "FLAG_" }, flag = true, value = { 173 FLAG_BYPASS_INTERRUPTION_POLICY, 174 FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF, 175 FLAG_INVALIDATE_SETTINGS_CACHE, 176 FLAG_PIPELINED_EFFECT, 177 FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE 178 }) 179 @Retention(RetentionPolicy.SOURCE) 180 public @interface Flag{} 181 182 /** 183 * Flag requesting vibration effect to be played even under limited interruptions. 184 * 185 * <p>Only privileged apps can ignore user settings that limit interruptions, and this 186 * flag will be ignored otherwise. 187 */ 188 public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 1; 189 190 /** 191 * Flag requesting vibration effect to be played even when user settings are disabling it. 192 * 193 * <p>Flag introduced to represent 194 * {@link android.view.HapticFeedbackConstants#FLAG_IGNORE_GLOBAL_SETTING} and 195 * {@link AudioAttributes#FLAG_BYPASS_MUTE}. 196 * 197 * <p>Only privileged apps can ignore user settings, and this flag will be ignored otherwise. 198 * 199 * @hide 200 */ 201 public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 1 << 1; 202 203 /** 204 * Flag requesting vibration effect to be played with fresh user settings values. 205 * 206 * <p>This flag is not protected by any permission, but vibrations that use it require an extra 207 * query of user vibration intensity settings, ringer mode and other controls that affect the 208 * vibration effect playback, which can increase the latency for the overall request. 209 * 210 * <p>This is intended to be used on scenarios where the user settings might have changed 211 * recently, and needs to be applied to this vibration, like settings controllers that preview 212 * newly set intensities to the user. 213 * 214 * @hide 215 */ 216 public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 1 << 2; 217 218 /** 219 * Flag requesting that this vibration effect be pipelined with other vibration effects from the 220 * same package that also carry this flag. 221 * 222 * <p>Pipelined effects won't cancel a running pipelined effect, but will instead play after 223 * it completes. However, only one pipelined effect can be waiting at a time - so if an effect 224 * is already waiting (but not running), it will be cancelled in favor of a newer one. 225 * 226 * @hide 227 */ 228 public static final int FLAG_PIPELINED_EFFECT = 1 << 3; 229 230 /** 231 * Flag requesting that this vibration effect to be played without applying the user 232 * intensity setting to scale the vibration. 233 * 234 * <p>The user setting is still applied to enable/disable the vibration, but the vibration 235 * effect strength will not be scaled based on the enabled setting value. 236 * 237 * <p>This is intended to be used on scenarios where the system needs to enforce a specific 238 * strength for the vibration effect, regardless of the user preference. Only privileged apps 239 * can ignore user settings, and this flag will be ignored otherwise. 240 * 241 * <p>If you need to bypass the user setting when it's disabling vibrations then this also 242 * needs the flag {@link #FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF} to be set. 243 * 244 * @hide 245 */ 246 public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE = 1 << 4; 247 248 /** 249 * All flags supported by vibrator service, update it when adding new flag. 250 * @hide 251 */ 252 public static final int FLAG_ALL_SUPPORTED = 253 FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF 254 | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT 255 | FLAG_BYPASS_USER_VIBRATION_INTENSITY_SCALE; 256 257 /** Creates a new {@link VibrationAttributes} instance with given usage. */ createForUsage(@sage int usage)258 public static @NonNull VibrationAttributes createForUsage(@Usage int usage) { 259 return new VibrationAttributes.Builder().setUsage(usage).build(); 260 } 261 262 private final int mUsage; 263 private final int mFlags; 264 private final int mOriginalAudioUsage; 265 private final int mCategory; 266 VibrationAttributes(@sage int usage, @AudioAttributes.AttributeUsage int audioUsage, @Flag int flags, @Category int category)267 private VibrationAttributes(@Usage int usage, @AudioAttributes.AttributeUsage int audioUsage, 268 @Flag int flags, @Category int category) { 269 mUsage = usage; 270 mOriginalAudioUsage = audioUsage; 271 mFlags = flags & FLAG_ALL_SUPPORTED; 272 mCategory = category; 273 } 274 275 /** 276 * Return the vibration usage class. 277 */ 278 @UsageClass getUsageClass()279 public int getUsageClass() { 280 return mUsage & USAGE_CLASS_MASK; 281 } 282 283 /** 284 * Return the vibration usage. 285 */ 286 @Usage getUsage()287 public int getUsage() { 288 return mUsage; 289 } 290 291 /** 292 * Return the original {@link AudioAttributes} used to create the vibration attributes. 293 * @hide 294 */ 295 @AudioAttributes.AttributeUsage getOriginalAudioUsage()296 public int getOriginalAudioUsage() { 297 return mOriginalAudioUsage; 298 } 299 300 /** 301 * Return the flags. 302 * @return a combined mask of all flags 303 */ 304 @Flag getFlags()305 public int getFlags() { 306 return mFlags; 307 } 308 309 /** 310 * Return the vibration category. 311 * 312 * <p>Vibration categories describe the source of the vibration, and it can be combined with 313 * the vibration usage to best match to a user setting, e.g. a vibration with usage touch and 314 * category keyboard can be used to control keyboard haptic feedback independently. 315 * 316 * @hide 317 */ 318 @Category getCategory()319 public int getCategory() { 320 return mCategory; 321 } 322 323 /** 324 * Check whether a flag is set 325 * @return true if a flag is set and false otherwise 326 */ isFlagSet(@lag int flag)327 public boolean isFlagSet(@Flag int flag) { 328 return (mFlags & flag) > 0; 329 } 330 331 /** 332 * Return {@link AudioAttributes} usage equivalent to {@link #getUsage()}. 333 * @return one of {@link AudioAttributes#SDK_USAGES} that represents {@link #getUsage()} 334 * @hide 335 */ 336 @TestApi 337 @AudioAttributes.AttributeUsage getAudioUsage()338 public int getAudioUsage() { 339 if (mOriginalAudioUsage != AudioAttributes.USAGE_UNKNOWN) { 340 // Return same audio usage set in the Builder. 341 return mOriginalAudioUsage; 342 } 343 // Return correct audio usage based on the vibration usage set in the Builder. 344 switch (mUsage) { 345 case USAGE_NOTIFICATION: 346 return AudioAttributes.USAGE_NOTIFICATION; 347 case USAGE_COMMUNICATION_REQUEST: 348 return AudioAttributes.USAGE_VOICE_COMMUNICATION; 349 case USAGE_RINGTONE: 350 return AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 351 case USAGE_TOUCH: 352 return AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; 353 case USAGE_ALARM: 354 return AudioAttributes.USAGE_ALARM; 355 case USAGE_ACCESSIBILITY: 356 return AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY; 357 case USAGE_MEDIA: 358 return AudioAttributes.USAGE_MEDIA; 359 default: 360 return AudioAttributes.USAGE_UNKNOWN; 361 } 362 } 363 364 @Override describeContents()365 public int describeContents() { 366 return 0; 367 } 368 369 @Override writeToParcel(@onNull Parcel dest, int flags)370 public void writeToParcel(@NonNull Parcel dest, int flags) { 371 dest.writeInt(mUsage); 372 dest.writeInt(mOriginalAudioUsage); 373 dest.writeInt(mFlags); 374 dest.writeInt(mCategory); 375 } 376 VibrationAttributes(Parcel src)377 private VibrationAttributes(Parcel src) { 378 mUsage = src.readInt(); 379 mOriginalAudioUsage = src.readInt(); 380 mFlags = src.readInt(); 381 mCategory = src.readInt(); 382 } 383 384 public static final @NonNull Parcelable.Creator<VibrationAttributes> 385 CREATOR = new Parcelable.Creator<VibrationAttributes>() { 386 public VibrationAttributes createFromParcel(Parcel p) { 387 return new VibrationAttributes(p); 388 } 389 public VibrationAttributes[] newArray(int size) { 390 return new VibrationAttributes[size]; 391 } 392 }; 393 394 @Override equals(@ullable Object o)395 public boolean equals(@Nullable Object o) { 396 if (this == o) { 397 return true; 398 } 399 if (o == null || getClass() != o.getClass()) { 400 return false; 401 } 402 VibrationAttributes rhs = (VibrationAttributes) o; 403 return mUsage == rhs.mUsage && mOriginalAudioUsage == rhs.mOriginalAudioUsage 404 && mFlags == rhs.mFlags && mCategory == rhs.mCategory; 405 } 406 407 @Override hashCode()408 public int hashCode() { 409 return Objects.hash(mUsage, mOriginalAudioUsage, mFlags, mCategory); 410 } 411 412 @Override toString()413 public String toString() { 414 return "VibrationAttributes{" 415 + "mUsage=" + usageToString() 416 + ", mAudioUsage= " + AudioAttributes.usageToString(mOriginalAudioUsage) 417 + ", mCategory=" + categoryToString() 418 + ", mFlags=" + mFlags 419 + '}'; 420 } 421 422 /** @hide */ usageToString()423 public String usageToString() { 424 return usageToString(mUsage); 425 } 426 427 /** @hide */ usageToString(@sage int usage)428 public static String usageToString(@Usage int usage) { 429 switch (usage) { 430 case USAGE_UNKNOWN: 431 return "UNKNOWN"; 432 case USAGE_ALARM: 433 return "ALARM"; 434 case USAGE_ACCESSIBILITY: 435 return "ACCESSIBILITY"; 436 case USAGE_RINGTONE: 437 return "RINGTONE"; 438 case USAGE_NOTIFICATION: 439 return "NOTIFICATION"; 440 case USAGE_COMMUNICATION_REQUEST: 441 return "COMMUNICATION_REQUEST"; 442 case USAGE_MEDIA: 443 return "MEDIA"; 444 case USAGE_TOUCH: 445 return "TOUCH"; 446 case USAGE_PHYSICAL_EMULATION: 447 return "PHYSICAL_EMULATION"; 448 case USAGE_HARDWARE_FEEDBACK: 449 return "HARDWARE_FEEDBACK"; 450 default: 451 return "unknown usage " + usage; 452 } 453 } 454 455 /** @hide */ categoryToString()456 public String categoryToString() { 457 return categoryToString(mCategory); 458 } 459 460 /** @hide */ categoryToString(@ategory int category)461 public static String categoryToString(@Category int category) { 462 switch (category) { 463 case CATEGORY_UNKNOWN: 464 return "UNKNOWN"; 465 case CATEGORY_KEYBOARD: 466 return "KEYBOARD"; 467 default: 468 return "unknown category " + category; 469 } 470 } 471 472 /** 473 * Builder class for {@link VibrationAttributes} objects. 474 * By default, all information is set to UNKNOWN. 475 */ 476 @android.ravenwood.annotation.RavenwoodKeepWholeClass 477 public static final class Builder { 478 private int mUsage = USAGE_UNKNOWN; 479 private int mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN; 480 private int mFlags = 0x0; 481 private int mCategory = CATEGORY_UNKNOWN; 482 483 /** 484 * Constructs a new Builder with the defaults. 485 */ Builder()486 public Builder() { 487 } 488 489 /** 490 * Constructs a new Builder from a given VibrationAttributes. 491 */ Builder(@ullable VibrationAttributes vib)492 public Builder(@Nullable VibrationAttributes vib) { 493 if (vib != null) { 494 mUsage = vib.mUsage; 495 mOriginalAudioUsage = vib.mOriginalAudioUsage; 496 mFlags = vib.mFlags; 497 mCategory = vib.mCategory; 498 } 499 } 500 501 /** 502 * Constructs a new Builder from AudioAttributes. 503 */ Builder(@onNull AudioAttributes audio)504 public Builder(@NonNull AudioAttributes audio) { 505 setUsage(audio); 506 setFlags(audio); 507 } 508 setUsage(@onNull AudioAttributes audio)509 private void setUsage(@NonNull AudioAttributes audio) { 510 mOriginalAudioUsage = audio.getUsage(); 511 switch (audio.getUsage()) { 512 case AudioAttributes.USAGE_NOTIFICATION: 513 case AudioAttributes.USAGE_NOTIFICATION_EVENT: 514 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 515 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 516 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 517 mUsage = USAGE_NOTIFICATION; 518 break; 519 case AudioAttributes.USAGE_VOICE_COMMUNICATION: 520 case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING: 521 case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: 522 case AudioAttributes.USAGE_ASSISTANT: 523 mUsage = USAGE_COMMUNICATION_REQUEST; 524 break; 525 case AudioAttributes.USAGE_NOTIFICATION_RINGTONE: 526 mUsage = USAGE_RINGTONE; 527 break; 528 case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY: 529 mUsage = USAGE_ACCESSIBILITY; 530 break; 531 case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION: 532 mUsage = USAGE_TOUCH; 533 break; 534 case AudioAttributes.USAGE_ALARM: 535 mUsage = USAGE_ALARM; 536 break; 537 case AudioAttributes.USAGE_MEDIA: 538 case AudioAttributes.USAGE_GAME: 539 mUsage = USAGE_MEDIA; 540 break; 541 default: 542 mUsage = USAGE_UNKNOWN; 543 } 544 } 545 setFlags(@onNull AudioAttributes audio)546 private void setFlags(@NonNull AudioAttributes audio) { 547 if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { 548 mFlags |= FLAG_BYPASS_INTERRUPTION_POLICY; 549 } 550 if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_MUTE) != 0) { 551 // Muted audio stream translates to vibration usage having the value 552 // Vibrator.VIBRATION_INTENSITY_OFF set in the user setting. 553 mFlags |= FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; 554 } 555 } 556 557 /** 558 * Combines all of the attributes that have been set and returns a new 559 * {@link VibrationAttributes} object. 560 * @return a new {@link VibrationAttributes} object 561 */ build()562 public @NonNull VibrationAttributes build() { 563 VibrationAttributes ans = new VibrationAttributes( 564 mUsage, mOriginalAudioUsage, mFlags, mCategory); 565 return ans; 566 } 567 568 /** 569 * Sets the attribute describing the type of the corresponding vibration. 570 * @param usage The type of usage for the vibration 571 * @return the same Builder instance. 572 */ setUsage(@sage int usage)573 public @NonNull Builder setUsage(@Usage int usage) { 574 mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN; 575 mUsage = usage; 576 return this; 577 } 578 579 /** 580 * Sets the attribute describing the category of the corresponding vibration. 581 * 582 * @param category The category for the vibration 583 * @return the same Builder instance. 584 * 585 * @hide 586 */ setCategory(@ategory int category)587 public @NonNull Builder setCategory(@Category int category) { 588 mCategory = category; 589 return this; 590 } 591 592 /** 593 * Sets only the flags specified in the bitmask, leaving the other supported flag values 594 * unchanged in the builder. 595 * 596 * @param flags Combination of flags to be set. 597 * @param mask Bit range that should be changed. 598 * @return the same Builder instance. 599 */ setFlags(@lag int flags, int mask)600 public @NonNull Builder setFlags(@Flag int flags, int mask) { 601 mask &= FLAG_ALL_SUPPORTED; 602 mFlags = (mFlags & ~mask) | (flags & mask); 603 return this; 604 } 605 606 /** 607 * Set all supported flags with given combination of flags, overriding any previous values 608 * set to this builder. 609 * 610 * @param flags combination of flags to be set. 611 * @return the same Builder instance. 612 * 613 * @hide 614 */ setFlags(@lag int flags)615 public @NonNull Builder setFlags(@Flag int flags) { 616 return setFlags(flags, FLAG_ALL_SUPPORTED); 617 } 618 } 619 } 620