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