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