Skip to content

Commit edbb380

Browse files
committed
Notification vibration improvements:
- When notifications vibrate as a fallback (that is, because they want to play a sound but the device is in vibrate mode), this no longer requires the VIBRATE permission. - As a bonus, if your notifications use DEFAULT_VIBRATE, you don't need the VIBRATE permission either. - If you specify a custom vibration pattern, you'll still need the VIBRATE permission for that. - Notifications vibrating in fallback mode use a different vibration pattern. - The DEFAULT_VIBRATE and fallback vibrate patterns are now specified in config.xml. Bug: 7531442 Change-Id: I7a2d8413d1becc53b9d31f0d1abbc2acc3f650c6
1 parent faa38a0 commit edbb380

File tree

3 files changed

+74
-8
lines changed

3 files changed

+74
-8
lines changed

core/res/res/values/config.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,4 +1000,25 @@
10001000
provisioning on some carriers, working around a bug (7305641)
10011001
where if the preferred is used we don't try the others. -->
10021002
<bool name="config_dontPreferApn">false</bool>
1003+
1004+
<!-- Vibrator pattern to be used as the default for notifications
1005+
that specify DEFAULT_VIBRATE.
1006+
-->
1007+
<integer-array name="config_defaultNotificationVibePattern">
1008+
<item>0</item>
1009+
<item>150</item>
1010+
<item>200</item>
1011+
<item>250</item>
1012+
</integer-array>
1013+
1014+
<!-- Vibrator pattern to be used as the default for notifications
1015+
that do not specify vibration but vibrate anyway because the device
1016+
is in vibrate mode.
1017+
-->
1018+
<integer-array name="config_notificationFallbackVibePattern">
1019+
<item>0</item>
1020+
<item>33</item>
1021+
<item>150</item>
1022+
<item>50</item>
1023+
</integer-array>
10031024
</resources>

core/res/res/values/symbols.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1525,6 +1525,8 @@
15251525
<java-symbol type="array" name="radioAttributes" />
15261526
<java-symbol type="array" name="config_oemUsbModeOverride" />
15271527
<java-symbol type="array" name="config_locationProviderPackageNames" />
1528+
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
1529+
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
15281530
<java-symbol type="bool" name="config_animateScreenLights" />
15291531
<java-symbol type="bool" name="config_automatic_brightness_available" />
15301532
<java-symbol type="bool" name="config_sf_limitedAlpha" />

services/java/com/android/server/NotificationManagerService.java

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ public class NotificationManagerService extends INotificationManager.Stub
101101
private static final int SHORT_DELAY = 2000; // 2 seconds
102102

103103
private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
104+
private static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
104105

105106
private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
106107
private static final boolean SCORE_ONGOING_HIGHER = false;
@@ -125,6 +126,9 @@ public class NotificationManagerService extends INotificationManager.Stub
125126
private int mDefaultNotificationLedOn;
126127
private int mDefaultNotificationLedOff;
127128

129+
private long[] mDefaultVibrationPattern;
130+
private long[] mFallbackVibrationPattern;
131+
128132
private boolean mSystemReady;
129133
private int mDisabledNotifications;
130134

@@ -596,6 +600,19 @@ public void update() {
596600
}
597601
}
598602

603+
static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
604+
int[] ar = r.getIntArray(resid);
605+
if (ar == null) {
606+
return def;
607+
}
608+
final int len = ar.length > maxlen ? maxlen : ar.length;
609+
long[] out = new long[len];
610+
for (int i=0; i<len; i++) {
611+
out[i] = ar[i];
612+
}
613+
return out;
614+
}
615+
599616
NotificationManagerService(Context context, StatusBarManagerService statusBar,
600617
LightsService lights)
601618
{
@@ -622,6 +639,16 @@ public void update() {
622639
mDefaultNotificationLedOff = resources.getInteger(
623640
com.android.internal.R.integer.config_defaultNotificationLedOff);
624641

642+
mDefaultVibrationPattern = getLongArray(resources,
643+
com.android.internal.R.array.config_defaultNotificationVibePattern,
644+
VIBRATE_PATTERN_MAXLEN,
645+
DEFAULT_VIBRATE_PATTERN);
646+
647+
mFallbackVibrationPattern = getLongArray(resources,
648+
com.android.internal.R.array.config_notificationFallbackVibePattern,
649+
VIBRATE_PATTERN_MAXLEN,
650+
DEFAULT_VIBRATE_PATTERN);
651+
625652
// Don't start allowing notifications until the setup wizard has run once.
626653
// After that, including subsequent boots, init with notifications turned on.
627654
// This works on the first boot because the setup wizard will toggle this
@@ -1086,24 +1113,40 @@ public void enqueueNotificationInternal(String pkg, int callingUid, int callingP
10861113
}
10871114

10881115
// vibrate
1116+
// Does the notification want to specify its own vibration?
1117+
final boolean hasCustomVibrate = notification.vibrate != null;
1118+
10891119
// new in 4.2: if there was supposed to be a sound and we're in vibrate mode,
1090-
// we always vibrate, even if no vibration was specified
1120+
// and no other vibration is specified, we apply the default vibration anyway
10911121
final boolean convertSoundToVibration =
1092-
notification.vibrate == null
1122+
!hasCustomVibrate
10931123
&& (useDefaultSound || notification.sound != null)
10941124
&& (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
10951125

1126+
// The DEFAULT_VIBRATE flag trumps any custom vibration.
10961127
final boolean useDefaultVibrate =
1097-
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0
1098-
|| convertSoundToVibration;
1128+
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
10991129

1100-
if ((useDefaultVibrate || notification.vibrate != null)
1130+
if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
11011131
&& !(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) {
11021132
mVibrateNotification = r;
11031133

1104-
mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN
1105-
: notification.vibrate,
1106-
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
1134+
if (useDefaultVibrate || convertSoundToVibration) {
1135+
// Escalate privileges so we can use the vibrator even if the notifying app
1136+
// does not have the VIBRATE permission.
1137+
long identity = Binder.clearCallingIdentity();
1138+
try {
1139+
mVibrator.vibrate(convertSoundToVibration ? mFallbackVibrationPattern
1140+
: mDefaultVibrationPattern,
1141+
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
1142+
} finally {
1143+
Binder.restoreCallingIdentity(identity);
1144+
}
1145+
} else if (notification.vibrate.length > 1) {
1146+
// If you want your own vibration pattern, you need the VIBRATE permission
1147+
mVibrator.vibrate(notification.vibrate,
1148+
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
1149+
}
11071150
}
11081151
}
11091152

0 commit comments

Comments
 (0)