/* * Copyright (C) 2022 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.vibrator; import static android.os.VibrationAttributes.USAGE_ACCESSIBILITY; import static android.os.VibrationAttributes.USAGE_ALARM; import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST; import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK; import static android.os.VibrationAttributes.USAGE_MEDIA; import static android.os.VibrationAttributes.USAGE_NOTIFICATION; import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION; import static android.os.VibrationAttributes.USAGE_RINGTONE; import static android.os.VibrationAttributes.USAGE_TOUCH; import static android.os.VibrationAttributes.USAGE_UNKNOWN; import android.annotation.Nullable; import android.content.res.Resources; import android.os.VibrationAttributes; import android.os.Vibrator; import android.os.Vibrator.VibrationIntensity; import android.util.IndentingPrintWriter; import java.io.PrintWriter; import java.util.Arrays; /** * List of device-specific internal vibration configuration loaded from platform config.xml. * *
This should not be public, but some individual values are exposed by {@link Vibrator} by * hidden methods, made available to Settings, SysUI and other platform client code. They can also * be individually exposed with the necessary permissions by the {@link Vibrator} service. * * @hide */ public class VibrationConfig { // TODO(b/191150049): move these to vibrator static config file private final float mHapticChannelMaxVibrationAmplitude; private final int mRampStepDurationMs; private final int mRampDownDurationMs; private final int mRequestVibrationParamsTimeoutMs; private final int[] mRequestVibrationParamsForUsages; private final boolean mIgnoreVibrationsOnWirelessCharger; @VibrationIntensity private final int mDefaultAlarmVibrationIntensity; @VibrationIntensity private final int mDefaultHapticFeedbackIntensity; @VibrationIntensity private final int mDefaultMediaVibrationIntensity; @VibrationIntensity private final int mDefaultNotificationVibrationIntensity; @VibrationIntensity private final int mDefaultRingVibrationIntensity; private final boolean mDefaultKeyboardVibrationEnabled; private final boolean mHasFixedKeyboardAmplitude; /** @hide */ public VibrationConfig(@Nullable Resources resources) { mHapticChannelMaxVibrationAmplitude = loadFloat(resources, com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude, 0); mRampDownDurationMs = loadInteger(resources, com.android.internal.R.integer.config_vibrationWaveformRampDownDuration, 0); mRampStepDurationMs = loadInteger(resources, com.android.internal.R.integer.config_vibrationWaveformRampStepDuration, 0); mRequestVibrationParamsTimeoutMs = loadInteger(resources, com.android.internal.R.integer.config_requestVibrationParamsTimeout, 0); mRequestVibrationParamsForUsages = loadIntArray(resources, com.android.internal.R.array.config_requestVibrationParamsForUsages); mIgnoreVibrationsOnWirelessCharger = loadBoolean(resources, com.android.internal.R.bool.config_ignoreVibrationsOnWirelessCharger, false); mDefaultKeyboardVibrationEnabled = loadBoolean(resources, com.android.internal.R.bool.config_defaultKeyboardVibrationEnabled, true); mHasFixedKeyboardAmplitude = loadFloat(resources, com.android.internal.R.dimen.config_keyboardHapticFeedbackFixedAmplitude, -1) > 0; mDefaultAlarmVibrationIntensity = loadDefaultIntensity(resources, com.android.internal.R.integer.config_defaultAlarmVibrationIntensity); mDefaultHapticFeedbackIntensity = loadDefaultIntensity(resources, com.android.internal.R.integer.config_defaultHapticFeedbackIntensity); mDefaultMediaVibrationIntensity = loadDefaultIntensity(resources, com.android.internal.R.integer.config_defaultMediaVibrationIntensity); mDefaultNotificationVibrationIntensity = loadDefaultIntensity(resources, com.android.internal.R.integer.config_defaultNotificationVibrationIntensity); mDefaultRingVibrationIntensity = loadDefaultIntensity(resources, com.android.internal.R.integer.config_defaultRingVibrationIntensity); } @VibrationIntensity private static int loadDefaultIntensity(@Nullable Resources res, int resId) { int defaultIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM; int value = loadInteger(res, resId, defaultIntensity); if (value < Vibrator.VIBRATION_INTENSITY_OFF || value > Vibrator.VIBRATION_INTENSITY_HIGH) { return defaultIntensity; } return value; } private static float loadFloat(@Nullable Resources res, int resId, float defaultValue) { return res != null ? res.getFloat(resId) : defaultValue; } private static int loadInteger(@Nullable Resources res, int resId, int defaultValue) { return res != null ? res.getInteger(resId) : defaultValue; } private static boolean loadBoolean(@Nullable Resources res, int resId, boolean defaultValue) { return res != null ? res.getBoolean(resId) : defaultValue; } private static int[] loadIntArray(@Nullable Resources res, int resId) { return res != null ? res.getIntArray(resId) : new int[0]; } /** * Return the maximum amplitude the vibrator can play using the audio haptic channels. * * @return a positive value representing the maximum absolute value the device can play signals * from audio haptic channels, or {@link Float#NaN NaN} if it's unknown. */ public float getHapticChannelMaximumAmplitude() { if (mHapticChannelMaxVibrationAmplitude <= 0) { return Float.NaN; } return mHapticChannelMaxVibrationAmplitude; } /** * The duration, in milliseconds, that should be applied to the ramp to turn off the vibrator * when a vibration is cancelled or finished at non-zero amplitude. */ public int getRampDownDurationMs() { if (mRampDownDurationMs < 0) { return 0; } return mRampDownDurationMs; } /** * The duration, in milliseconds, that the vibrator control service will wait for new * vibration params. */ public int getRequestVibrationParamsTimeoutMs() { return Math.max(mRequestVibrationParamsTimeoutMs, 0); } /** * The list of usages that should request vibration params before they are played. These * usages don't have strong latency requirements, e.g. ringtone and notification, and can be * slightly delayed. */ public int[] getRequestVibrationParamsForUsages() { return mRequestVibrationParamsForUsages; } /** * The duration, in milliseconds, that should be applied to convert vibration effect's * {@link android.os.vibrator.RampSegment} to a {@link android.os.vibrator.StepSegment} on * devices without PWLE support. */ public int getRampStepDurationMs() { if (mRampStepDurationMs < 0) { return 0; } return mRampStepDurationMs; } /** * Whether or not vibrations are ignored if the device is on a wireless charger. * *
This may be the case if vibration during wireless charging causes unwanted results, like * moving the device out of alignment with the charging pad. */ public boolean ignoreVibrationsOnWirelessCharger() { return mIgnoreVibrationsOnWirelessCharger; } /** * Whether keyboard vibration settings is enabled by default. * @hide */ public boolean isDefaultKeyboardVibrationEnabled() { return mDefaultKeyboardVibrationEnabled; } /** * Whether the device has a fixed amplitude for keyboard. * @hide */ public boolean hasFixedKeyboardAmplitude() { return mHasFixedKeyboardAmplitude; } /** Get the default vibration intensity for given usage. */ @VibrationIntensity public int getDefaultVibrationIntensity(@VibrationAttributes.Usage int usage) { switch (usage) { case USAGE_ALARM: return mDefaultAlarmVibrationIntensity; case USAGE_NOTIFICATION: case USAGE_COMMUNICATION_REQUEST: return mDefaultNotificationVibrationIntensity; case USAGE_RINGTONE: return mDefaultRingVibrationIntensity; case USAGE_TOUCH: case USAGE_HARDWARE_FEEDBACK: case USAGE_PHYSICAL_EMULATION: case USAGE_ACCESSIBILITY: return mDefaultHapticFeedbackIntensity; case USAGE_MEDIA: case USAGE_UNKNOWN: // fall through default: return mDefaultMediaVibrationIntensity; } } @Override public String toString() { return "VibrationConfig{" + "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger + ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude + ", mRampStepDurationMs=" + mRampStepDurationMs + ", mRampDownDurationMs=" + mRampDownDurationMs + ", mRequestVibrationParamsForUsages=" + Arrays.toString(getRequestVibrationParamsForUsagesNames()) + ", mRequestVibrationParamsTimeoutMs=" + mRequestVibrationParamsTimeoutMs + ", mDefaultAlarmIntensity=" + mDefaultAlarmVibrationIntensity + ", mDefaultHapticFeedbackIntensity=" + mDefaultHapticFeedbackIntensity + ", mDefaultMediaIntensity=" + mDefaultMediaVibrationIntensity + ", mDefaultNotificationIntensity=" + mDefaultNotificationVibrationIntensity + ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity + ", mDefaultKeyboardVibrationEnabled=" + mDefaultKeyboardVibrationEnabled + "}"; } /** * Write current settings into given {@link PrintWriter}, skipping the default settings. * * @hide */ public void dumpWithoutDefaultSettings(IndentingPrintWriter pw) { pw.println("VibrationConfig:"); pw.increaseIndent(); pw.println("ignoreVibrationsOnWirelessCharger = " + mIgnoreVibrationsOnWirelessCharger); pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude); pw.println("rampStepDurationMs = " + mRampStepDurationMs); pw.println("rampDownDurationMs = " + mRampDownDurationMs); pw.println("requestVibrationParamsForUsages = " + Arrays.toString(getRequestVibrationParamsForUsagesNames())); pw.println("requestVibrationParamsTimeoutMs = " + mRequestVibrationParamsTimeoutMs); pw.decreaseIndent(); } private String[] getRequestVibrationParamsForUsagesNames() { int usagesCount = mRequestVibrationParamsForUsages.length; String[] names = new String[usagesCount]; for (int i = 0; i < usagesCount; i++) { names[i] = VibrationAttributes.usageToString(mRequestVibrationParamsForUsages[i]); } return names; } }