1 /*
2  * Copyright (C) 2006 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.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SystemService;
23 import android.app.ActivityThread;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.content.Context;
26 import android.media.AudioAttributes;
27 import android.util.Log;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 
32 /**
33  * Class that operates the vibrator on the device.
34  * <p>
35  * If your process exits, any vibration you started will stop.
36  * </p>
37  */
38 @SystemService(Context.VIBRATOR_SERVICE)
39 public abstract class Vibrator {
40     private static final String TAG = "Vibrator";
41 
42     /**
43      * Vibration intensity: no vibrations.
44      * @hide
45      */
46     public static final int VIBRATION_INTENSITY_OFF = 0;
47 
48     /**
49      * Vibration intensity: low.
50      * @hide
51      */
52     public static final int VIBRATION_INTENSITY_LOW = 1;
53 
54     /**
55      * Vibration intensity: medium.
56      * @hide
57      */
58     public static final int VIBRATION_INTENSITY_MEDIUM = 2;
59 
60     /**
61      * Vibration intensity: high.
62      * @hide
63      */
64     public static final int VIBRATION_INTENSITY_HIGH = 3;
65 
66     /** @hide */
67     @Retention(RetentionPolicy.SOURCE)
68     @IntDef(prefix = { "VIBRATION_INTENSITY_" }, value = {
69         VIBRATION_INTENSITY_OFF,
70         VIBRATION_INTENSITY_LOW,
71         VIBRATION_INTENSITY_MEDIUM,
72         VIBRATION_INTENSITY_HIGH
73     })
74     public @interface VibrationIntensity{}
75 
76     private final String mPackageName;
77     // The default vibration intensity level for haptic feedback.
78     @VibrationIntensity
79     private int mDefaultHapticFeedbackIntensity;
80     // The default vibration intensity level for notifications.
81     @VibrationIntensity
82     private int mDefaultNotificationVibrationIntensity;
83     // The default vibration intensity level for ringtones.
84     @VibrationIntensity
85     private int mDefaultRingVibrationIntensity;
86 
87     /**
88      * @hide to prevent subclassing from outside of the framework
89      */
90     @UnsupportedAppUsage
Vibrator()91     public Vibrator() {
92         mPackageName = ActivityThread.currentPackageName();
93         final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
94         loadVibrationIntensities(ctx);
95     }
96 
97     /**
98      * @hide to prevent subclassing from outside of the framework
99      */
Vibrator(Context context)100     protected Vibrator(Context context) {
101         mPackageName = context.getOpPackageName();
102         loadVibrationIntensities(context);
103     }
104 
loadVibrationIntensities(Context context)105     private void loadVibrationIntensities(Context context) {
106         mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context,
107                 com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
108         mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context,
109                 com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
110         mDefaultRingVibrationIntensity = loadDefaultIntensity(context,
111                 com.android.internal.R.integer.config_defaultRingVibrationIntensity);
112     }
113 
loadDefaultIntensity(Context ctx, int resId)114     private int loadDefaultIntensity(Context ctx, int resId) {
115         return ctx != null ? ctx.getResources().getInteger(resId) : VIBRATION_INTENSITY_MEDIUM;
116     }
117 
118     /**
119      * Get the default vibration intensity for haptic feedback.
120      * @hide
121      */
getDefaultHapticFeedbackIntensity()122     public int getDefaultHapticFeedbackIntensity() {
123         return mDefaultHapticFeedbackIntensity;
124     }
125 
126     /**
127      * Get the default vibration intensity for notifications.
128      * @hide
129      */
getDefaultNotificationVibrationIntensity()130     public int getDefaultNotificationVibrationIntensity() {
131         return mDefaultNotificationVibrationIntensity;
132     }
133 
134     /** Get the default vibration intensity for ringtones.
135      * @hide
136      */
getDefaultRingVibrationIntensity()137     public int getDefaultRingVibrationIntensity() {
138         return mDefaultRingVibrationIntensity;
139     }
140 
141     /**
142      * Check whether the hardware has a vibrator.
143      *
144      * @return True if the hardware has a vibrator, else false.
145      */
hasVibrator()146     public abstract boolean hasVibrator();
147 
148     /**
149      * Check whether the vibrator has amplitude control.
150      *
151      * @return True if the hardware can control the amplitude of the vibrations, otherwise false.
152      */
hasAmplitudeControl()153     public abstract boolean hasAmplitudeControl();
154 
155     /**
156      * Configure an always-on haptics effect.
157      *
158      * @param alwaysOnId The board-specific always-on ID to configure.
159      * @param effect Vibration effect to assign to always-on id. Passing null will disable it.
160      * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
161      *        specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
162      *        {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
163      *        vibrations associated with incoming calls. May only be null when effect is null.
164      * @hide
165      */
166     @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes)167     public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect,
168             @Nullable AudioAttributes attributes) {
169         return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes);
170     }
171 
172     /**
173      * @hide
174      */
175     @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes)176     public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId,
177             @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) {
178         Log.w(TAG, "Always-on effects aren't supported");
179         return false;
180     }
181 
182     /**
183      * Vibrate constantly for the specified period of time.
184      *
185      * @param milliseconds The number of milliseconds to vibrate.
186      *
187      * @deprecated Use {@link #vibrate(VibrationEffect)} instead.
188      */
189     @Deprecated
190     @RequiresPermission(android.Manifest.permission.VIBRATE)
vibrate(long milliseconds)191     public void vibrate(long milliseconds) {
192         vibrate(milliseconds, null);
193     }
194 
195     /**
196      * Vibrate constantly for the specified period of time.
197      *
198      * @param milliseconds The number of milliseconds to vibrate.
199      * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
200      *        specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
201      *        {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
202      *        vibrations associated with incoming calls.
203      *
204      * @deprecated Use {@link #vibrate(VibrationEffect, AudioAttributes)} instead.
205      */
206     @Deprecated
207     @RequiresPermission(android.Manifest.permission.VIBRATE)
vibrate(long milliseconds, AudioAttributes attributes)208     public void vibrate(long milliseconds, AudioAttributes attributes) {
209         try {
210             // This ignores all exceptions to stay compatible with pre-O implementations.
211             VibrationEffect effect =
212                     VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE);
213             vibrate(effect, attributes);
214         } catch (IllegalArgumentException iae) {
215             Log.e(TAG, "Failed to create VibrationEffect", iae);
216         }
217     }
218 
219     /**
220      * Vibrate with a given pattern.
221      *
222      * <p>
223      * Pass in an array of ints that are the durations for which to turn on or off
224      * the vibrator in milliseconds.  The first value indicates the number of milliseconds
225      * to wait before turning the vibrator on.  The next value indicates the number of milliseconds
226      * for which to keep the vibrator on before turning it off.  Subsequent values alternate
227      * between durations in milliseconds to turn the vibrator off or to turn the vibrator on.
228      * </p><p>
229      * To cause the pattern to repeat, pass the index into the pattern array at which
230      * to start the repeat, or -1 to disable repeating.
231      * </p>
232      *
233      * @param pattern an array of longs of times for which to turn the vibrator on or off.
234      * @param repeat the index into pattern at which to repeat, or -1 if
235      *        you don't want to repeat.
236      *
237      * @deprecated Use {@link #vibrate(VibrationEffect)} instead.
238      */
239     @Deprecated
240     @RequiresPermission(android.Manifest.permission.VIBRATE)
vibrate(long[] pattern, int repeat)241     public void vibrate(long[] pattern, int repeat) {
242         vibrate(pattern, repeat, null);
243     }
244 
245     /**
246      * Vibrate with a given pattern.
247      *
248      * <p>
249      * Pass in an array of ints that are the durations for which to turn on or off
250      * the vibrator in milliseconds.  The first value indicates the number of milliseconds
251      * to wait before turning the vibrator on.  The next value indicates the number of milliseconds
252      * for which to keep the vibrator on before turning it off.  Subsequent values alternate
253      * between durations in milliseconds to turn the vibrator off or to turn the vibrator on.
254      * </p><p>
255      * To cause the pattern to repeat, pass the index into the pattern array at which
256      * to start the repeat, or -1 to disable repeating.
257      * </p>
258      *
259      * @param pattern an array of longs of times for which to turn the vibrator on or off.
260      * @param repeat the index into pattern at which to repeat, or -1 if
261      *        you don't want to repeat.
262      * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
263      *        specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
264      *        {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for
265      *        vibrations associated with incoming calls.
266      *
267      * @deprecated Use {@link #vibrate(VibrationEffect, AudioAttributes)} instead.
268      */
269     @Deprecated
270     @RequiresPermission(android.Manifest.permission.VIBRATE)
vibrate(long[] pattern, int repeat, AudioAttributes attributes)271     public void vibrate(long[] pattern, int repeat, AudioAttributes attributes) {
272         // This call needs to continue throwing ArrayIndexOutOfBoundsException but ignore all other
273         // exceptions for compatibility purposes
274         if (repeat < -1 || repeat >= pattern.length) {
275             Log.e(TAG, "vibrate called with repeat index out of bounds" +
276                     " (pattern.length=" + pattern.length + ", index=" + repeat + ")");
277             throw new ArrayIndexOutOfBoundsException();
278         }
279 
280         try {
281             vibrate(VibrationEffect.createWaveform(pattern, repeat), attributes);
282         } catch (IllegalArgumentException iae) {
283             Log.e(TAG, "Failed to create VibrationEffect", iae);
284         }
285     }
286 
287     @RequiresPermission(android.Manifest.permission.VIBRATE)
vibrate(VibrationEffect vibe)288     public void vibrate(VibrationEffect vibe) {
289         vibrate(vibe, null);
290     }
291 
292     @RequiresPermission(android.Manifest.permission.VIBRATE)
vibrate(VibrationEffect vibe, AudioAttributes attributes)293     public void vibrate(VibrationEffect vibe, AudioAttributes attributes) {
294         vibrate(Process.myUid(), mPackageName, vibe, null, attributes);
295     }
296 
297     /**
298      * Like {@link #vibrate(int, String, VibrationEffect, AudioAttributes)}, but allows the
299      * caller to specify the vibration is owned by someone else and set reason for vibration.
300      * @hide
301      */
302     @RequiresPermission(android.Manifest.permission.VIBRATE)
vibrate(int uid, String opPkg, VibrationEffect vibe, String reason, AudioAttributes attributes)303     public abstract void vibrate(int uid, String opPkg, VibrationEffect vibe,
304             String reason, AudioAttributes attributes);
305 
306     /**
307      * Turn the vibrator off.
308      */
309     @RequiresPermission(android.Manifest.permission.VIBRATE)
cancel()310     public abstract void cancel();
311 }
312