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 FLAG_INVALIDATE_SETTINGS_CACHE, 150 FLAG_PIPELINED_EFFECT 151 }) 152 @Retention(RetentionPolicy.SOURCE) 153 public @interface Flag{} 154 155 /** 156 * Flag requesting vibration effect to be played even under limited interruptions. 157 * 158 * <p>Only privileged apps can ignore user settings that limit interruptions, and this 159 * flag will be ignored otherwise. 160 */ 161 public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 1; 162 163 /** 164 * Flag requesting vibration effect to be played even when user settings are disabling it. 165 * 166 * <p>Flag introduced to represent 167 * {@link android.view.HapticFeedbackConstants#FLAG_IGNORE_GLOBAL_SETTING} and 168 * {@link AudioAttributes#FLAG_BYPASS_MUTE}. 169 * 170 * @hide 171 */ 172 public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 1 << 1; 173 174 /** 175 * Flag requesting vibration effect to be played with fresh user settings values. 176 * 177 * <p>This flag is not protected by any permission, but vibrations that use it require an extra 178 * query of user vibration intensity settings, ringer mode and other controls that affect the 179 * vibration effect playback, which can increase the latency for the overall request. 180 * 181 * <p>This is intended to be used on scenarios where the user settings might have changed 182 * recently, and needs to be applied to this vibration, like settings controllers that preview 183 * newly set intensities to the user. 184 * 185 * @hide 186 */ 187 public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 1 << 2; 188 189 /** 190 * Flag requesting that this vibration effect be pipelined with other vibration effects from the 191 * same package that also carry this flag. 192 * 193 * <p>Pipelined effects won't cancel a running pipelined effect, but will instead play after 194 * it completes. However, only one pipelined effect can be waiting at a time - so if an effect 195 * is already waiting (but not running), it will be cancelled in favor of a newer one. 196 * 197 * @hide 198 */ 199 public static final int FLAG_PIPELINED_EFFECT = 1 << 3; 200 201 /** 202 * All flags supported by vibrator service, update it when adding new flag. 203 * @hide 204 */ 205 public static final int FLAG_ALL_SUPPORTED = 206 FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF 207 | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT; 208 209 /** Creates a new {@link VibrationAttributes} instance with given usage. */ createForUsage(@sage int usage)210 public static @NonNull VibrationAttributes createForUsage(@Usage int usage) { 211 return new VibrationAttributes.Builder().setUsage(usage).build(); 212 } 213 214 private final int mUsage; 215 private final int mFlags; 216 private final int mOriginalAudioUsage; 217 VibrationAttributes(@sage int usage, @AudioAttributes.AttributeUsage int audioUsage, @Flag int flags)218 private VibrationAttributes(@Usage int usage, @AudioAttributes.AttributeUsage int audioUsage, 219 @Flag int flags) { 220 mUsage = usage; 221 mOriginalAudioUsage = audioUsage; 222 mFlags = flags & FLAG_ALL_SUPPORTED; 223 } 224 225 /** 226 * Return the vibration usage class. 227 */ 228 @UsageClass getUsageClass()229 public int getUsageClass() { 230 return mUsage & USAGE_CLASS_MASK; 231 } 232 233 /** 234 * Return the vibration usage. 235 */ 236 @Usage getUsage()237 public int getUsage() { 238 return mUsage; 239 } 240 241 /** 242 * Return the flags. 243 * @return a combined mask of all flags 244 */ 245 @Flag getFlags()246 public int getFlags() { 247 return mFlags; 248 } 249 250 /** 251 * Check whether a flag is set 252 * @return true if a flag is set and false otherwise 253 */ isFlagSet(@lag int flag)254 public boolean isFlagSet(@Flag int flag) { 255 return (mFlags & flag) > 0; 256 } 257 258 /** 259 * Return {@link AudioAttributes} usage equivalent to {@link #getUsage()}. 260 * @return one of {@link AudioAttributes#SDK_USAGES} that represents {@link #getUsage()} 261 * @hide 262 */ 263 @TestApi 264 @AudioAttributes.AttributeUsage getAudioUsage()265 public int getAudioUsage() { 266 if (mOriginalAudioUsage != AudioAttributes.USAGE_UNKNOWN) { 267 // Return same audio usage set in the Builder. 268 return mOriginalAudioUsage; 269 } 270 // Return correct audio usage based on the vibration usage set in the Builder. 271 switch (mUsage) { 272 case USAGE_NOTIFICATION: 273 return AudioAttributes.USAGE_NOTIFICATION; 274 case USAGE_COMMUNICATION_REQUEST: 275 return AudioAttributes.USAGE_VOICE_COMMUNICATION; 276 case USAGE_RINGTONE: 277 return AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 278 case USAGE_TOUCH: 279 return AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; 280 case USAGE_ALARM: 281 return AudioAttributes.USAGE_ALARM; 282 case USAGE_ACCESSIBILITY: 283 return AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY; 284 case USAGE_MEDIA: 285 return AudioAttributes.USAGE_MEDIA; 286 default: 287 return AudioAttributes.USAGE_UNKNOWN; 288 } 289 } 290 291 @Override describeContents()292 public int describeContents() { 293 return 0; 294 } 295 296 @Override writeToParcel(@onNull Parcel dest, int flags)297 public void writeToParcel(@NonNull Parcel dest, int flags) { 298 dest.writeInt(mUsage); 299 dest.writeInt(mOriginalAudioUsage); 300 dest.writeInt(mFlags); 301 } 302 VibrationAttributes(Parcel src)303 private VibrationAttributes(Parcel src) { 304 mUsage = src.readInt(); 305 mOriginalAudioUsage = src.readInt(); 306 mFlags = src.readInt(); 307 } 308 309 public static final @NonNull Parcelable.Creator<VibrationAttributes> 310 CREATOR = new Parcelable.Creator<VibrationAttributes>() { 311 public VibrationAttributes createFromParcel(Parcel p) { 312 return new VibrationAttributes(p); 313 } 314 public VibrationAttributes[] newArray(int size) { 315 return new VibrationAttributes[size]; 316 } 317 }; 318 319 @Override equals(@ullable Object o)320 public boolean equals(@Nullable Object o) { 321 if (this == o) { 322 return true; 323 } 324 if (o == null || getClass() != o.getClass()) { 325 return false; 326 } 327 VibrationAttributes rhs = (VibrationAttributes) o; 328 return mUsage == rhs.mUsage && mOriginalAudioUsage == rhs.mOriginalAudioUsage 329 && mFlags == rhs.mFlags; 330 } 331 332 @Override hashCode()333 public int hashCode() { 334 return Objects.hash(mUsage, mOriginalAudioUsage, mFlags); 335 } 336 337 @Override toString()338 public String toString() { 339 return "VibrationAttributes:" 340 + " Usage=" + usageToString() 341 + " Audio Usage= " + AudioAttributes.usageToString(mOriginalAudioUsage) 342 + " Flags=" + mFlags; 343 } 344 345 /** @hide */ usageToString()346 public String usageToString() { 347 return usageToString(mUsage); 348 } 349 350 /** @hide */ usageToString(@sage int usage)351 public static String usageToString(@Usage int usage) { 352 switch (usage) { 353 case USAGE_UNKNOWN: 354 return "UNKNOWN"; 355 case USAGE_ALARM: 356 return "ALARM"; 357 case USAGE_ACCESSIBILITY: 358 return "ACCESSIBILITY"; 359 case USAGE_RINGTONE: 360 return "RINGTONE"; 361 case USAGE_NOTIFICATION: 362 return "NOTIFICATION"; 363 case USAGE_COMMUNICATION_REQUEST: 364 return "COMMUNICATION_REQUEST"; 365 case USAGE_MEDIA: 366 return "MEDIA"; 367 case USAGE_TOUCH: 368 return "TOUCH"; 369 case USAGE_PHYSICAL_EMULATION: 370 return "PHYSICAL_EMULATION"; 371 case USAGE_HARDWARE_FEEDBACK: 372 return "HARDWARE_FEEDBACK"; 373 default: 374 return "unknown usage " + usage; 375 } 376 } 377 378 /** 379 * Builder class for {@link VibrationAttributes} objects. 380 * By default, all information is set to UNKNOWN. 381 */ 382 public static final class Builder { 383 private int mUsage = USAGE_UNKNOWN; 384 private int mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN; 385 private int mFlags = 0x0; 386 387 /** 388 * Constructs a new Builder with the defaults. 389 */ Builder()390 public Builder() { 391 } 392 393 /** 394 * Constructs a new Builder from a given VibrationAttributes. 395 */ Builder(@ullable VibrationAttributes vib)396 public Builder(@Nullable VibrationAttributes vib) { 397 if (vib != null) { 398 mUsage = vib.mUsage; 399 mOriginalAudioUsage = vib.mOriginalAudioUsage; 400 mFlags = vib.mFlags; 401 } 402 } 403 404 /** 405 * Constructs a new Builder from AudioAttributes. 406 */ Builder(@onNull AudioAttributes audio)407 public Builder(@NonNull AudioAttributes audio) { 408 setUsage(audio); 409 setFlags(audio); 410 } 411 setUsage(@onNull AudioAttributes audio)412 private void setUsage(@NonNull AudioAttributes audio) { 413 mOriginalAudioUsage = audio.getUsage(); 414 switch (audio.getUsage()) { 415 case AudioAttributes.USAGE_NOTIFICATION: 416 case AudioAttributes.USAGE_NOTIFICATION_EVENT: 417 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 418 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 419 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 420 mUsage = USAGE_NOTIFICATION; 421 break; 422 case AudioAttributes.USAGE_VOICE_COMMUNICATION: 423 case AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING: 424 case AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE: 425 case AudioAttributes.USAGE_ASSISTANT: 426 mUsage = USAGE_COMMUNICATION_REQUEST; 427 break; 428 case AudioAttributes.USAGE_NOTIFICATION_RINGTONE: 429 mUsage = USAGE_RINGTONE; 430 break; 431 case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY: 432 mUsage = USAGE_ACCESSIBILITY; 433 break; 434 case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION: 435 mUsage = USAGE_TOUCH; 436 break; 437 case AudioAttributes.USAGE_ALARM: 438 mUsage = USAGE_ALARM; 439 break; 440 case AudioAttributes.USAGE_MEDIA: 441 case AudioAttributes.USAGE_GAME: 442 mUsage = USAGE_MEDIA; 443 break; 444 default: 445 mUsage = USAGE_UNKNOWN; 446 } 447 } 448 setFlags(@onNull AudioAttributes audio)449 private void setFlags(@NonNull AudioAttributes audio) { 450 if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) { 451 mFlags |= FLAG_BYPASS_INTERRUPTION_POLICY; 452 } 453 if ((audio.getAllFlags() & AudioAttributes.FLAG_BYPASS_MUTE) != 0) { 454 // Muted audio stream translates to vibration usage having the value 455 // Vibrator.VIBRATION_INTENSITY_OFF set in the user setting. 456 mFlags |= FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF; 457 } 458 } 459 460 /** 461 * Combines all of the attributes that have been set and returns a new 462 * {@link VibrationAttributes} object. 463 * @return a new {@link VibrationAttributes} object 464 */ build()465 public @NonNull VibrationAttributes build() { 466 VibrationAttributes ans = new VibrationAttributes(mUsage, mOriginalAudioUsage, mFlags); 467 return ans; 468 } 469 470 /** 471 * Sets the attribute describing the type of the corresponding vibration. 472 * @param usage The type of usage for the vibration 473 * @return the same Builder instance. 474 */ setUsage(@sage int usage)475 public @NonNull Builder setUsage(@Usage int usage) { 476 mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN; 477 mUsage = usage; 478 return this; 479 } 480 481 /** 482 * Sets only the flags specified in the bitmask, leaving the other supported flag values 483 * unchanged in the builder. 484 * 485 * @param flags Combination of flags to be set. 486 * @param mask Bit range that should be changed. 487 * @return the same Builder instance. 488 */ setFlags(@lag int flags, int mask)489 public @NonNull Builder setFlags(@Flag int flags, int mask) { 490 mask &= FLAG_ALL_SUPPORTED; 491 mFlags = (mFlags & ~mask) | (flags & mask); 492 return this; 493 } 494 495 /** 496 * Set all supported flags with given combination of flags, overriding any previous values 497 * set to this builder. 498 * 499 * @param flags combination of flags to be set. 500 * @return the same Builder instance. 501 * 502 * @hide 503 */ setFlags(@lag int flags)504 public @NonNull Builder setFlags(@Flag int flags) { 505 return setFlags(flags, FLAG_ALL_SUPPORTED); 506 } 507 } 508 } 509