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