blob: f47aa487744a9d3a2d3d71968a135514984eae89 [file] [log] [blame]
/*
* Copyright (C) 2021 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 com.android.server.notification;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.media.AudioAttributes;
import android.os.Process;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.util.Slog;
import com.android.internal.R;
import com.android.server.pm.PackageManagerService;
import java.util.Arrays;
/**
* NotificationManagerService helper for functionality related to the vibrator.
*/
public final class VibratorHelper {
private static final String TAG = "NotificationVibratorHelper";
private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
private final Vibrator mVibrator;
private final long[] mDefaultPattern;
private final long[] mFallbackPattern;
public VibratorHelper(Context context) {
mVibrator = context.getSystemService(Vibrator.class);
mDefaultPattern = getLongArray(
context.getResources(),
com.android.internal.R.array.config_defaultNotificationVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
mFallbackPattern = getLongArray(context.getResources(),
R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
}
/**
* Safely create a {@link VibrationEffect} from given vibration {@code pattern}.
*
* <p>This method returns {@code null} if the pattern is also {@code null} or invalid.
*
* @param pattern The off/on vibration pattern, where each item is a duration in milliseconds.
* @param insistent {@code true} if the vibration should loop until it is cancelled.
*/
@Nullable
public static VibrationEffect createWaveformVibration(@Nullable long[] pattern,
boolean insistent) {
try {
if (pattern != null) {
return VibrationEffect.createWaveform(pattern, /* repeat= */ insistent ? 0 : -1);
}
} catch (IllegalArgumentException e) {
Slog.e(TAG, "Error creating vibration waveform with pattern: "
+ Arrays.toString(pattern));
}
return null;
}
/**
* Vibrate the device with given {@code effect}.
*
* <p>We need to vibrate as "android" so we can breakthrough DND.
*/
public void vibrate(VibrationEffect effect, AudioAttributes attrs, String reason) {
mVibrator.vibrate(Process.SYSTEM_UID, PackageManagerService.PLATFORM_PACKAGE_NAME,
effect, reason, attrs);
}
/** Stop all notification vibrations (ringtone, alarm, notification usages). */
public void cancelVibration() {
int usageFilter =
VibrationAttributes.USAGE_CLASS_ALARM | ~VibrationAttributes.USAGE_CLASS_MASK;
mVibrator.cancel(usageFilter);
}
/**
* Creates a vibration to be used as fallback when the device is in vibrate mode.
*
* @param insistent {@code true} if the vibration should loop until it is cancelled.
*/
public VibrationEffect createFallbackVibration(boolean insistent) {
return createWaveformVibration(mFallbackPattern, insistent);
}
/**
* Creates a vibration to be used by notifications without a custom pattern.
*
* @param insistent {@code true} if the vibration should loop until it is cancelled.
*/
public VibrationEffect createDefaultVibration(boolean insistent) {
return createWaveformVibration(mDefaultPattern, insistent);
}
private static long[] getLongArray(Resources resources, int resId, int maxLength, long[] def) {
int[] ar = resources.getIntArray(resId);
if (ar == null) {
return def;
}
final int len = ar.length > maxLength ? maxLength : ar.length;
long[] out = new long[len];
for (int i = 0; i < len; i++) {
out[i] = ar[i];
}
return out;
}
}