• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.vibrator;
18 
19 import static android.os.VibrationAttributes.USAGE_ACCESSIBILITY;
20 import static android.os.VibrationAttributes.USAGE_ALARM;
21 import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST;
22 import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK;
23 import static android.os.VibrationAttributes.USAGE_IME_FEEDBACK;
24 import static android.os.VibrationAttributes.USAGE_MEDIA;
25 import static android.os.VibrationAttributes.USAGE_NOTIFICATION;
26 import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION;
27 import static android.os.VibrationAttributes.USAGE_RINGTONE;
28 import static android.os.VibrationAttributes.USAGE_TOUCH;
29 import static android.os.VibrationAttributes.USAGE_UNKNOWN;
30 
31 import android.annotation.Nullable;
32 import android.content.res.Resources;
33 import android.os.VibrationAttributes;
34 import android.os.Vibrator;
35 import android.os.Vibrator.VibrationIntensity;
36 import android.util.IndentingPrintWriter;
37 
38 import java.io.PrintWriter;
39 import java.util.Arrays;
40 
41 /**
42  * List of device-specific internal vibration configuration loaded from platform config.xml.
43  *
44  * <p>This should not be public, but some individual values are exposed by {@link Vibrator} by
45  * hidden methods, made available to Settings, SysUI and other platform client code. They can also
46  * be individually exposed with the necessary permissions by the {@link Vibrator} service.
47  *
48  * @hide
49  */
50 public class VibrationConfig {
51 
52     /**
53      * Hardcoded default scale level gain to be applied between each scale level to define their
54      * scale factor value.
55      *
56      * <p>Default gain defined as 3 dBs.
57      */
58     private static final float DEFAULT_SCALE_LEVEL_GAIN = 1.4f;
59 
60     /**
61      * Hardcoded default amplitude to be used when device config is invalid, i.e. not in [1,255].
62      */
63     private static final int DEFAULT_AMPLITUDE = 255;
64 
65     // TODO(b/191150049): move these to vibrator static config file
66     private final float mHapticChannelMaxVibrationAmplitude;
67     private final int mDefaultVibrationAmplitude;
68     private final int mRampStepDurationMs;
69     private final int mRampDownDurationMs;
70     private final int mRequestVibrationParamsTimeoutMs;
71     private final int[] mRequestVibrationParamsForUsages;
72 
73     private final boolean mIgnoreVibrationsOnWirelessCharger;
74 
75     @VibrationIntensity
76     private final int mDefaultAlarmVibrationIntensity;
77     @VibrationIntensity
78     private final int mDefaultHapticFeedbackIntensity;
79     @VibrationIntensity
80     private final int mDefaultMediaVibrationIntensity;
81     @VibrationIntensity
82     private final int mDefaultNotificationVibrationIntensity;
83     @VibrationIntensity
84     private final int mDefaultRingVibrationIntensity;
85     @VibrationIntensity
86     private final int mDefaultKeyboardVibrationIntensity;
87 
88     private final boolean mKeyboardVibrationSettingsSupported;
89     private final int mVibrationPipelineMaxDurationMs;
90 
91     /** @hide */
VibrationConfig(@ullable Resources resources)92     public VibrationConfig(@Nullable Resources resources) {
93         mDefaultVibrationAmplitude = resources.getInteger(
94                 com.android.internal.R.integer.config_defaultVibrationAmplitude);
95         mHapticChannelMaxVibrationAmplitude = loadFloat(resources,
96                 com.android.internal.R.dimen.config_hapticChannelMaxVibrationAmplitude);
97         mRampDownDurationMs = loadInteger(resources,
98                 com.android.internal.R.integer.config_vibrationWaveformRampDownDuration, 0);
99         mRampStepDurationMs = loadInteger(resources,
100                 com.android.internal.R.integer.config_vibrationWaveformRampStepDuration, 0);
101         mRequestVibrationParamsTimeoutMs = loadInteger(resources,
102                 com.android.internal.R.integer.config_requestVibrationParamsTimeout, 0);
103         mRequestVibrationParamsForUsages = loadIntArray(resources,
104                 com.android.internal.R.array.config_requestVibrationParamsForUsages);
105 
106         mIgnoreVibrationsOnWirelessCharger = loadBoolean(resources,
107                 com.android.internal.R.bool.config_ignoreVibrationsOnWirelessCharger);
108         mKeyboardVibrationSettingsSupported = loadBoolean(resources,
109                 com.android.internal.R.bool.config_keyboardVibrationSettingsSupported);
110         mVibrationPipelineMaxDurationMs = loadInteger(resources,
111                 com.android.internal.R.integer.config_vibrationPipelineMaxDuration, 0);
112 
113         mDefaultAlarmVibrationIntensity = loadDefaultIntensity(resources,
114                 com.android.internal.R.integer.config_defaultAlarmVibrationIntensity);
115         mDefaultHapticFeedbackIntensity = loadDefaultIntensity(resources,
116                 com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
117         mDefaultMediaVibrationIntensity = loadDefaultIntensity(resources,
118                 com.android.internal.R.integer.config_defaultMediaVibrationIntensity);
119         mDefaultNotificationVibrationIntensity = loadDefaultIntensity(resources,
120                 com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
121         mDefaultRingVibrationIntensity = loadDefaultIntensity(resources,
122                 com.android.internal.R.integer.config_defaultRingVibrationIntensity);
123         mDefaultKeyboardVibrationIntensity = loadDefaultIntensity(resources,
124                 com.android.internal.R.integer.config_defaultKeyboardVibrationIntensity);
125     }
126 
127     @VibrationIntensity
loadDefaultIntensity(@ullable Resources res, int resId)128     private static int loadDefaultIntensity(@Nullable Resources res, int resId) {
129         int defaultIntensity = Vibrator.VIBRATION_INTENSITY_MEDIUM;
130         int value = loadInteger(res, resId, defaultIntensity);
131         if (value < Vibrator.VIBRATION_INTENSITY_OFF || value > Vibrator.VIBRATION_INTENSITY_HIGH) {
132             return defaultIntensity;
133         }
134         return value;
135     }
136 
loadFloat(@ullable Resources res, int resId)137     private static float loadFloat(@Nullable Resources res, int resId) {
138         return res != null ? res.getFloat(resId) : 0f;
139     }
140 
loadInteger(@ullable Resources res, int resId, int defaultValue)141     private static int loadInteger(@Nullable Resources res, int resId, int defaultValue) {
142         return res != null ? res.getInteger(resId) : defaultValue;
143     }
144 
loadBoolean(@ullable Resources res, int resId)145     private static boolean loadBoolean(@Nullable Resources res, int resId) {
146         return res != null && res.getBoolean(resId);
147     }
148 
loadIntArray(@ullable Resources res, int resId)149     private static int[] loadIntArray(@Nullable Resources res, int resId) {
150         return res != null ? res.getIntArray(resId) : new int[0];
151     }
152 
153     /**
154      * Return the maximum amplitude the vibrator can play using the audio haptic channels.
155      *
156      * @return a positive value representing the maximum absolute value the device can play signals
157      * from audio haptic channels, or {@link Float#NaN NaN} if it's unknown.
158      */
getHapticChannelMaximumAmplitude()159     public float getHapticChannelMaximumAmplitude() {
160         if (mHapticChannelMaxVibrationAmplitude <= 0) {
161             return Float.NaN;
162         }
163         return mHapticChannelMaxVibrationAmplitude;
164     }
165 
166     /**
167      * Return the device default vibration amplitude value to replace the
168      * {@link android.os.VibrationEffect#DEFAULT_AMPLITUDE} constant.
169      */
getDefaultVibrationAmplitude()170     public int getDefaultVibrationAmplitude() {
171         if (mDefaultVibrationAmplitude < 1 || mDefaultVibrationAmplitude > 255) {
172             return DEFAULT_AMPLITUDE;
173         }
174         return mDefaultVibrationAmplitude;
175     }
176 
177     /**
178      * Return the device default gain to be applied between scale levels to define the scale factor
179      * for each level.
180      */
getDefaultVibrationScaleLevelGain()181     public float getDefaultVibrationScaleLevelGain() {
182         // TODO(b/356407380): add device config for this
183         return DEFAULT_SCALE_LEVEL_GAIN;
184     }
185 
186     /**
187      * The duration, in milliseconds, that should be applied to the ramp to turn off the vibrator
188      * when a vibration is cancelled or finished at non-zero amplitude.
189      */
getRampDownDurationMs()190     public int getRampDownDurationMs() {
191         if (mRampDownDurationMs < 0) {
192             return 0;
193         }
194         return mRampDownDurationMs;
195     }
196 
197     /**
198      * The duration, in milliseconds, that the vibrator control service will wait for new
199      * vibration params.
200      */
getRequestVibrationParamsTimeoutMs()201     public int getRequestVibrationParamsTimeoutMs() {
202         return Math.max(mRequestVibrationParamsTimeoutMs, 0);
203     }
204 
205     /**
206      * The list of usages that should request vibration params before they are played. These
207      * usages don't have strong latency requirements, e.g. ringtone and notification, and can be
208      * slightly delayed.
209      */
getRequestVibrationParamsForUsages()210     public int[] getRequestVibrationParamsForUsages() {
211         return mRequestVibrationParamsForUsages;
212     }
213 
214     /**
215      * The duration, in milliseconds, that should be applied to convert vibration effect's
216      * {@link android.os.vibrator.RampSegment} to a {@link android.os.vibrator.StepSegment} on
217      * devices without PWLE support.
218      */
getRampStepDurationMs()219     public int getRampStepDurationMs() {
220         if (mRampStepDurationMs < 0) {
221             return 0;
222         }
223         return mRampStepDurationMs;
224     }
225 
226     /**
227      * The max duration, in milliseconds, allowed for pipelining vibration requests.
228      *
229      * <p>If the ongoing vibration duration is shorter than this threshold then it should be allowed
230      * to finish before the next vibration can start. If the ongoing vibration is longer than this
231      * then it should be cancelled when it's superseded for the new one.
232      *
233      * @return the max duration allowed for vibration effect to finish before the next request, or
234      * zero to disable effect pipelining.
235      */
getVibrationPipelineMaxDurationMs()236     public int getVibrationPipelineMaxDurationMs() {
237         if (mVibrationPipelineMaxDurationMs < 0) {
238             return 0;
239         }
240         return mVibrationPipelineMaxDurationMs;
241     }
242 
243     /**
244      * Whether or not vibrations are ignored if the device is on a wireless charger.
245      *
246      * <p>This may be the case if vibration during wireless charging causes unwanted results, like
247      * moving the device out of alignment with the charging pad.
248      */
ignoreVibrationsOnWirelessCharger()249     public boolean ignoreVibrationsOnWirelessCharger() {
250         return mIgnoreVibrationsOnWirelessCharger;
251     }
252 
253     /**
254      * Whether the device support keyboard vibration settings.
255      * @hide
256      */
isKeyboardVibrationSettingsSupported()257     public boolean isKeyboardVibrationSettingsSupported() {
258         return mKeyboardVibrationSettingsSupported;
259     }
260 
261     /** Get the default vibration intensity for given usage. */
262     @VibrationIntensity
getDefaultVibrationIntensity(@ibrationAttributes.Usage int usage)263     public int getDefaultVibrationIntensity(@VibrationAttributes.Usage int usage) {
264         switch (usage) {
265             case USAGE_ALARM:
266                 return mDefaultAlarmVibrationIntensity;
267             case USAGE_NOTIFICATION:
268             case USAGE_COMMUNICATION_REQUEST:
269                 return mDefaultNotificationVibrationIntensity;
270             case USAGE_RINGTONE:
271                 return mDefaultRingVibrationIntensity;
272             case USAGE_TOUCH:
273             case USAGE_HARDWARE_FEEDBACK:
274             case USAGE_PHYSICAL_EMULATION:
275             case USAGE_ACCESSIBILITY:
276                 return mDefaultHapticFeedbackIntensity;
277             case USAGE_IME_FEEDBACK:
278                 return isKeyboardVibrationSettingsSupported()
279                         ? mDefaultKeyboardVibrationIntensity : mDefaultHapticFeedbackIntensity;
280             case USAGE_MEDIA:
281             case USAGE_UNKNOWN:
282                 // fall through
283             default:
284                 return mDefaultMediaVibrationIntensity;
285         }
286     }
287 
288     @Override
toString()289     public String toString() {
290         return "VibrationConfig{"
291                 + "mIgnoreVibrationsOnWirelessCharger=" + mIgnoreVibrationsOnWirelessCharger
292                 + ", mDefaultVibrationAmplitude=" + mDefaultVibrationAmplitude
293                 + ", mHapticChannelMaxVibrationAmplitude=" + mHapticChannelMaxVibrationAmplitude
294                 + ", mRampStepDurationMs=" + mRampStepDurationMs
295                 + ", mRampDownDurationMs=" + mRampDownDurationMs
296                 + ", mRequestVibrationParamsForUsages="
297                 + Arrays.toString(getRequestVibrationParamsForUsagesNames())
298                 + ", mRequestVibrationParamsTimeoutMs=" + mRequestVibrationParamsTimeoutMs
299                 + ", mDefaultAlarmIntensity=" + mDefaultAlarmVibrationIntensity
300                 + ", mDefaultHapticFeedbackIntensity=" + mDefaultHapticFeedbackIntensity
301                 + ", mDefaultMediaIntensity=" + mDefaultMediaVibrationIntensity
302                 + ", mDefaultNotificationIntensity=" + mDefaultNotificationVibrationIntensity
303                 + ", mDefaultRingIntensity=" + mDefaultRingVibrationIntensity
304                 + ", mDefaultKeyboardIntensity=" + mDefaultKeyboardVibrationIntensity
305                 + ", mKeyboardVibrationSettingsSupported=" + mKeyboardVibrationSettingsSupported
306                 + "}";
307     }
308 
309     /**
310      * Write current settings into given {@link PrintWriter}, skipping the default settings.
311      *
312      * @hide
313      */
dumpWithoutDefaultSettings(IndentingPrintWriter pw)314     public void dumpWithoutDefaultSettings(IndentingPrintWriter pw) {
315         pw.println("VibrationConfig:");
316         pw.increaseIndent();
317         pw.println("ignoreVibrationsOnWirelessCharger = " + mIgnoreVibrationsOnWirelessCharger);
318         pw.println("defaultVibrationAmplitude = " + mDefaultVibrationAmplitude);
319         pw.println("hapticChannelMaxAmplitude = " + mHapticChannelMaxVibrationAmplitude);
320         pw.println("rampStepDurationMs = " + mRampStepDurationMs);
321         pw.println("rampDownDurationMs = " + mRampDownDurationMs);
322         pw.println("requestVibrationParamsForUsages = "
323                 + Arrays.toString(getRequestVibrationParamsForUsagesNames()));
324         pw.println("requestVibrationParamsTimeoutMs = " + mRequestVibrationParamsTimeoutMs);
325         pw.decreaseIndent();
326     }
327 
getRequestVibrationParamsForUsagesNames()328     private String[] getRequestVibrationParamsForUsagesNames() {
329         int usagesCount = mRequestVibrationParamsForUsages.length;
330         String[] names = new String[usagesCount];
331         for (int i = 0; i < usagesCount; i++) {
332             names[i] = VibrationAttributes.usageToString(mRequestVibrationParamsForUsages[i]);
333         }
334 
335         return names;
336     }
337 }
338