| /* |
| * Copyright (C) 2006 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.os; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.RequiresPermission; |
| import android.annotation.SystemService; |
| import android.app.ActivityThread; |
| import android.compat.annotation.UnsupportedAppUsage; |
| import android.content.Context; |
| import android.media.AudioAttributes; |
| import android.util.Log; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * Class that operates the vibrator on the device. |
| * <p> |
| * If your process exits, any vibration you started will stop. |
| * </p> |
| */ |
| @SystemService(Context.VIBRATOR_SERVICE) |
| public abstract class Vibrator { |
| private static final String TAG = "Vibrator"; |
| |
| /** |
| * Vibration intensity: no vibrations. |
| * |
| * @hide |
| */ |
| public static final int VIBRATION_INTENSITY_OFF = 0; |
| |
| /** |
| * Vibration intensity: low. |
| * |
| * @hide |
| */ |
| public static final int VIBRATION_INTENSITY_LOW = 1; |
| |
| /** |
| * Vibration intensity: medium. |
| * |
| * @hide |
| */ |
| public static final int VIBRATION_INTENSITY_MEDIUM = 2; |
| |
| /** |
| * Vibration intensity: high. |
| * |
| * @hide |
| */ |
| public static final int VIBRATION_INTENSITY_HIGH = 3; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef(prefix = {"VIBRATION_INTENSITY_"}, value = { |
| VIBRATION_INTENSITY_OFF, |
| VIBRATION_INTENSITY_LOW, |
| VIBRATION_INTENSITY_MEDIUM, |
| VIBRATION_INTENSITY_HIGH |
| }) |
| public @interface VibrationIntensity { |
| } |
| |
| private final String mPackageName; |
| // The default vibration intensity level for haptic feedback. |
| @VibrationIntensity |
| private int mDefaultHapticFeedbackIntensity; |
| // The default vibration intensity level for notifications. |
| @VibrationIntensity |
| private int mDefaultNotificationVibrationIntensity; |
| // The default vibration intensity level for ringtones. |
| @VibrationIntensity |
| private int mDefaultRingVibrationIntensity; |
| |
| /** |
| * @hide to prevent subclassing from outside of the framework |
| */ |
| @UnsupportedAppUsage |
| public Vibrator() { |
| mPackageName = ActivityThread.currentPackageName(); |
| final Context ctx = ActivityThread.currentActivityThread().getSystemContext(); |
| loadVibrationIntensities(ctx); |
| } |
| |
| /** |
| * @hide to prevent subclassing from outside of the framework |
| */ |
| protected Vibrator(Context context) { |
| mPackageName = context.getOpPackageName(); |
| loadVibrationIntensities(context); |
| } |
| |
| private void loadVibrationIntensities(Context context) { |
| mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context, |
| com.android.internal.R.integer.config_defaultHapticFeedbackIntensity); |
| mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context, |
| com.android.internal.R.integer.config_defaultNotificationVibrationIntensity); |
| mDefaultRingVibrationIntensity = loadDefaultIntensity(context, |
| com.android.internal.R.integer.config_defaultRingVibrationIntensity); |
| } |
| |
| private int loadDefaultIntensity(Context ctx, int resId) { |
| return ctx != null ? ctx.getResources().getInteger(resId) : VIBRATION_INTENSITY_MEDIUM; |
| } |
| |
| /** |
| * Get the default vibration intensity for haptic feedback. |
| * |
| * @hide |
| */ |
| public int getDefaultHapticFeedbackIntensity() { |
| return mDefaultHapticFeedbackIntensity; |
| } |
| |
| /** |
| * Get the default vibration intensity for notifications. |
| * |
| * @hide |
| */ |
| public int getDefaultNotificationVibrationIntensity() { |
| return mDefaultNotificationVibrationIntensity; |
| } |
| |
| /** |
| * Get the default vibration intensity for ringtones. |
| * |
| * @hide |
| */ |
| public int getDefaultRingVibrationIntensity() { |
| return mDefaultRingVibrationIntensity; |
| } |
| |
| /** |
| * Check whether the hardware has a vibrator. |
| * |
| * @return True if the hardware has a vibrator, else false. |
| */ |
| public abstract boolean hasVibrator(); |
| |
| /** |
| * Check whether the vibrator has amplitude control. |
| * |
| * @return True if the hardware can control the amplitude of the vibrations, otherwise false. |
| */ |
| public abstract boolean hasAmplitudeControl(); |
| |
| /** |
| * Configure an always-on haptics effect. |
| * |
| * @param alwaysOnId The board-specific always-on ID to configure. |
| * @param effect Vibration effect to assign to always-on id. Passing null will disable it. |
| * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, |
| * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or |
| * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for |
| * vibrations associated with incoming calls. May only be null when effect is |
| * null. |
| * @hide |
| */ |
| @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) |
| public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect, |
| @Nullable AudioAttributes attributes) { |
| return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes); |
| } |
| |
| /** |
| * @hide |
| */ |
| @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) |
| public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, |
| @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) { |
| Log.w(TAG, "Always-on effects aren't supported"); |
| return false; |
| } |
| |
| /** |
| * Vibrate constantly for the specified period of time. |
| * |
| * @param milliseconds The number of milliseconds to vibrate. |
| * @deprecated Use {@link #vibrate(VibrationEffect)} instead. |
| */ |
| @Deprecated |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public void vibrate(long milliseconds) { |
| vibrate(milliseconds, null); |
| } |
| |
| /** |
| * Vibrate constantly for the specified period of time. |
| * |
| * @param milliseconds The number of milliseconds to vibrate. |
| * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, |
| * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or |
| * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for |
| * vibrations associated with incoming calls. |
| * @deprecated Use {@link #vibrate(VibrationEffect, AudioAttributes)} instead. |
| */ |
| @Deprecated |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public void vibrate(long milliseconds, AudioAttributes attributes) { |
| try { |
| // This ignores all exceptions to stay compatible with pre-O implementations. |
| VibrationEffect effect = |
| VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE); |
| vibrate(effect, attributes); |
| } catch (IllegalArgumentException iae) { |
| Log.e(TAG, "Failed to create VibrationEffect", iae); |
| } |
| } |
| |
| /** |
| * Vibrate with a given pattern. |
| * |
| * <p> |
| * Pass in an array of ints that are the durations for which to turn on or off |
| * the vibrator in milliseconds. The first value indicates the number of milliseconds |
| * to wait before turning the vibrator on. The next value indicates the number of milliseconds |
| * for which to keep the vibrator on before turning it off. Subsequent values alternate |
| * between durations in milliseconds to turn the vibrator off or to turn the vibrator on. |
| * </p><p> |
| * To cause the pattern to repeat, pass the index into the pattern array at which |
| * to start the repeat, or -1 to disable repeating. |
| * </p> |
| * |
| * @param pattern an array of longs of times for which to turn the vibrator on or off. |
| * @param repeat the index into pattern at which to repeat, or -1 if |
| * you don't want to repeat. |
| * @deprecated Use {@link #vibrate(VibrationEffect)} instead. |
| */ |
| @Deprecated |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public void vibrate(long[] pattern, int repeat) { |
| vibrate(pattern, repeat, null); |
| } |
| |
| /** |
| * Vibrate with a given pattern. |
| * |
| * <p> |
| * Pass in an array of ints that are the durations for which to turn on or off |
| * the vibrator in milliseconds. The first value indicates the number of milliseconds |
| * to wait before turning the vibrator on. The next value indicates the number of milliseconds |
| * for which to keep the vibrator on before turning it off. Subsequent values alternate |
| * between durations in milliseconds to turn the vibrator off or to turn the vibrator on. |
| * </p><p> |
| * To cause the pattern to repeat, pass the index into the pattern array at which |
| * to start the repeat, or -1 to disable repeating. |
| * </p> |
| * |
| * @param pattern an array of longs of times for which to turn the vibrator on or off. |
| * @param repeat the index into pattern at which to repeat, or -1 if |
| * you don't want to repeat. |
| * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, |
| * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or |
| * {@link AudioAttributes#USAGE_NOTIFICATION_RINGTONE} for |
| * vibrations associated with incoming calls. |
| * @deprecated Use {@link #vibrate(VibrationEffect, AudioAttributes)} instead. |
| */ |
| @Deprecated |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public void vibrate(long[] pattern, int repeat, AudioAttributes attributes) { |
| // This call needs to continue throwing ArrayIndexOutOfBoundsException but ignore all other |
| // exceptions for compatibility purposes |
| if (repeat < -1 || repeat >= pattern.length) { |
| Log.e(TAG, "vibrate called with repeat index out of bounds" + |
| " (pattern.length=" + pattern.length + ", index=" + repeat + ")"); |
| throw new ArrayIndexOutOfBoundsException(); |
| } |
| |
| try { |
| vibrate(VibrationEffect.createWaveform(pattern, repeat), attributes); |
| } catch (IllegalArgumentException iae) { |
| Log.e(TAG, "Failed to create VibrationEffect", iae); |
| } |
| } |
| |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public void vibrate(VibrationEffect vibe) { |
| vibrate(vibe, null); |
| } |
| |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public void vibrate(VibrationEffect vibe, AudioAttributes attributes) { |
| vibrate(Process.myUid(), mPackageName, vibe, null, attributes); |
| } |
| |
| /** |
| * Like {@link #vibrate(VibrationEffect, AudioAttributes)}, but allows the |
| * caller to specify the vibration is owned by someone else and set reason for vibration. |
| * |
| * @hide |
| */ |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public abstract void vibrate(int uid, String opPkg, VibrationEffect vibe, |
| String reason, AudioAttributes attributes); |
| |
| /** |
| * Query whether the vibrator supports the given effects. |
| * |
| * If the returned array is {@code null}, the hardware doesn't support querying its supported |
| * effects. It may support any or all effects, but there's no way to programmatically know |
| * whether a {@link #vibrate} call will be successful. |
| * |
| * If the returned array is non-null, then it will be the same length as the query array and |
| * the value at a given index will contain whether the effect at that same index in the |
| * querying array is supported or not. |
| * |
| * @param effectIds Which effects to query for. |
| * @return Whether the effects are supported. Null when the hardware doesn't tell us what it |
| * supports. |
| */ |
| @Nullable |
| public boolean[] areEffectsSupported( |
| @NonNull @VibrationEffect.EffectType int... effectIds) { |
| return new boolean[effectIds.length]; |
| } |
| |
| /** |
| * Query whether the vibrator supports all of the given effects. |
| * |
| * If the result is {@code null}, the hardware doesn't support querying its supported |
| * effects. It may support any or all effects, but there's no way to programmatically know |
| * whether a {@link #vibrate} call will be successful. |
| * |
| * If the returned array is non-null, then it will return whether all of the effects are |
| * supported by the hardware. |
| * |
| * @param effectIds Which effects to query for. |
| * @return Whether the effects are supported. {@code null} when the hardware doesn't tell us |
| * what it supports. |
| */ |
| @Nullable |
| public Boolean areAllEffectsSupported( |
| @NonNull @VibrationEffect.EffectType int... effectIds) { |
| for (boolean supported : areEffectsSupported(effectIds)) { |
| if (!supported) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Query whether the vibrator supports the given primitives. |
| * |
| * The returned array will be the same length as the query array and the value at a given index |
| * will contain whether the effect at that same index in the querying array is supported or |
| * not. |
| * |
| * @param primitiveIds Which primitives to query for. |
| * @return Whether the primitives are supported. |
| */ |
| @NonNull |
| public boolean[] arePrimitivesSupported( |
| @NonNull @VibrationEffect.Composition.Primitive int... primitiveIds) { |
| return new boolean[primitiveIds.length]; |
| } |
| |
| /** |
| * Query whether the vibrator supports all of the given primitives. |
| * |
| * @param primitiveIds Which primitives to query for. |
| * @return Whether primitives effects are supported. |
| */ |
| public boolean areAllPrimitivesSupported( |
| @NonNull @VibrationEffect.Composition.Primitive int... primitiveIds) { |
| for (boolean supported : arePrimitivesSupported(primitiveIds)) { |
| if (!supported) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Turn the vibrator off. |
| */ |
| @RequiresPermission(android.Manifest.permission.VIBRATE) |
| public abstract void cancel(); |
| } |