All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.notification.VibratorHelper Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * 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.content.res.TypedArray;
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;
    @Nullable private final float[] mDefaultPwlePattern;
    @Nullable private final float[] mFallbackPwlePattern;

    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);
        mDefaultPwlePattern = getFloatArray(context.getResources(),
                com.android.internal.R.array.config_defaultNotificationVibeWaveform);
        mFallbackPwlePattern = getFloatArray(context.getResources(),
                com.android.internal.R.array.config_notificationFallbackVibeWaveform);
    }

    /**
     * Safely create a {@link VibrationEffect} from given vibration {@code pattern}.
     *
     * 

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; } /** * Safely create a {@link VibrationEffect} from given waveform description. * *

The waveform is described by a sequence of values for target amplitude, frequency and * duration, that are forwarded to * {@link VibrationEffect.WaveformBuilder#addRamp(float, float, int)}. * *

This method returns {@code null} if the pattern is also {@code null} or invalid. * * @param values The list of values describing the waveform as a sequence of target amplitude, * frequency and duration. * @param insistent {@code true} if the vibration should loop until it is cancelled. */ @Nullable public static VibrationEffect createPwleWaveformVibration(@Nullable float[] values, boolean insistent) { try { if (values == null) { return null; } int length = values.length; // The waveform is described by triples (amplitude, frequency, duration) if ((length == 0) || (length % 3 != 0)) { return null; } VibrationEffect.WaveformBuilder waveformBuilder = VibrationEffect.startWaveform(); for (int i = 0; i < length; i += 3) { waveformBuilder.addRamp(/* amplitude= */ values[i], /* frequency= */ values[i + 1], /* duration= */ (int) values[i + 2]); } if (insistent) { return waveformBuilder.build(/* repeat= */ 0); } return waveformBuilder.build(); } catch (IllegalArgumentException e) { Slog.e(TAG, "Error creating vibration PWLE waveform with pattern: " + Arrays.toString(values)); } return null; } /** * Vibrate the device with given {@code effect}. * *

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) { if (mVibrator.hasFrequencyControl()) { VibrationEffect effect = createPwleWaveformVibration(mFallbackPwlePattern, insistent); if (effect != null) { return effect; } } 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) { if (mVibrator.hasFrequencyControl()) { VibrationEffect effect = createPwleWaveformVibration(mDefaultPwlePattern, insistent); if (effect != null) { return effect; } } return createWaveformVibration(mDefaultPattern, insistent); } @Nullable private static float[] getFloatArray(Resources resources, int resId) { TypedArray array = resources.obtainTypedArray(resId); try { float[] values = new float[array.length()]; for (int i = 0; i < values.length; i++) { values[i] = array.getFloat(i, Float.NaN); if (Float.isNaN(values[i])) { return null; } } return values; } finally { array.recycle(); } } 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; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy