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