Notification vibration improvements: [DO NOT MERGE]

- 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 same
   vibration pattern but can be changed easily in future.
 - The DEFAULT_VIBRATE and fallback vibrate patterns are now
   specified in config.xml.

Bug: 7531442
Change-Id: I7a2d8413d1becc53b9d31f0d1abbc2acc3f650c6
This commit is contained in:
Daniel Sandler
2012-11-13 20:49:47 -08:00
committed by Dave Burke
parent 721b370c5a
commit aaec726948
3 changed files with 74 additions and 8 deletions

View File

@@ -1000,4 +1000,25 @@
provisioning on some carriers, working around a bug (7305641) provisioning on some carriers, working around a bug (7305641)
where if the preferred is used we don't try the others. --> where if the preferred is used we don't try the others. -->
<bool name="config_dontPreferApn">false</bool> <bool name="config_dontPreferApn">false</bool>
<!-- Vibrator pattern to be used as the default for notifications
that specify DEFAULT_VIBRATE.
-->
<integer-array name="config_defaultNotificationVibePattern">
<item>0</item>
<item>250</item>
<item>250</item>
<item>250</item>
</integer-array>
<!-- Vibrator pattern to be used as the default for notifications
that do not specify vibration but vibrate anyway because the device
is in vibrate mode.
-->
<integer-array name="config_notificationFallbackVibePattern">
<item>0</item>
<item>250</item>
<item>250</item>
<item>250</item>
</integer-array>
</resources> </resources>

View File

@@ -1525,6 +1525,8 @@
<java-symbol type="array" name="radioAttributes" /> <java-symbol type="array" name="radioAttributes" />
<java-symbol type="array" name="config_oemUsbModeOverride" /> <java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="array" name="config_locationProviderPackageNames" /> <java-symbol type="array" name="config_locationProviderPackageNames" />
<java-symbol type="array" name="config_defaultNotificationVibePattern" />
<java-symbol type="array" name="config_notificationFallbackVibePattern" />
<java-symbol type="bool" name="config_animateScreenLights" /> <java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" /> <java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" /> <java-symbol type="bool" name="config_sf_limitedAlpha" />

View File

@@ -101,6 +101,7 @@ public class NotificationManagerService extends INotificationManager.Stub
private static final int SHORT_DELAY = 2000; // 2 seconds private static final int SHORT_DELAY = 2000; // 2 seconds
private static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250}; 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 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION; private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
private static final boolean SCORE_ONGOING_HIGHER = false; private static final boolean SCORE_ONGOING_HIGHER = false;
@@ -125,6 +126,9 @@ public class NotificationManagerService extends INotificationManager.Stub
private int mDefaultNotificationLedOn; private int mDefaultNotificationLedOn;
private int mDefaultNotificationLedOff; private int mDefaultNotificationLedOff;
private long[] mDefaultVibrationPattern;
private long[] mFallbackVibrationPattern;
private boolean mSystemReady; private boolean mSystemReady;
private int mDisabledNotifications; private int mDisabledNotifications;
@@ -596,6 +600,19 @@ public class NotificationManagerService extends INotificationManager.Stub
} }
} }
static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
int[] ar = r.getIntArray(resid);
if (ar == null) {
return def;
}
final int len = ar.length > maxlen ? maxlen : ar.length;
long[] out = new long[len];
for (int i=0; i<len; i++) {
out[i] = ar[i];
}
return out;
}
NotificationManagerService(Context context, StatusBarManagerService statusBar, NotificationManagerService(Context context, StatusBarManagerService statusBar,
LightsService lights) LightsService lights)
{ {
@@ -622,6 +639,16 @@ public class NotificationManagerService extends INotificationManager.Stub
mDefaultNotificationLedOff = resources.getInteger( mDefaultNotificationLedOff = resources.getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOff); com.android.internal.R.integer.config_defaultNotificationLedOff);
mDefaultVibrationPattern = getLongArray(resources,
com.android.internal.R.array.config_defaultNotificationVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
mFallbackVibrationPattern = getLongArray(resources,
com.android.internal.R.array.config_notificationFallbackVibePattern,
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);
// Don't start allowing notifications until the setup wizard has run once. // Don't start allowing notifications until the setup wizard has run once.
// After that, including subsequent boots, init with notifications turned on. // After that, including subsequent boots, init with notifications turned on.
// This works on the first boot because the setup wizard will toggle this // This works on the first boot because the setup wizard will toggle this
@@ -1086,24 +1113,40 @@ public class NotificationManagerService extends INotificationManager.Stub
} }
// vibrate // vibrate
// Does the notification want to specify its own vibration?
final boolean hasCustomVibrate = notification.vibrate != null;
// new in 4.2: if there was supposed to be a sound and we're in vibrate mode, // new in 4.2: if there was supposed to be a sound and we're in vibrate mode,
// we always vibrate, even if no vibration was specified // and no other vibration is specified, we apply the default vibration anyway
final boolean convertSoundToVibration = final boolean convertSoundToVibration =
notification.vibrate == null !hasCustomVibrate
&& (useDefaultSound || notification.sound != null) && (useDefaultSound || notification.sound != null)
&& (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE); && (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
// The DEFAULT_VIBRATE flag trumps any custom vibration.
final boolean useDefaultVibrate = final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
|| convertSoundToVibration;
if ((useDefaultVibrate || notification.vibrate != null) if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
&& !(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) { && !(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotification = r; mVibrateNotification = r;
mVibrator.vibrate(useDefaultVibrate ? DEFAULT_VIBRATE_PATTERN if (useDefaultVibrate || convertSoundToVibration) {
: notification.vibrate, // Escalate privileges so we can use the vibrator even if the notifying app
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1); // does not have the VIBRATE permission.
long identity = Binder.clearCallingIdentity();
try {
mVibrator.vibrate(convertSoundToVibration ? mFallbackVibrationPattern
: mDefaultVibrationPattern,
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
} finally {
Binder.restoreCallingIdentity(identity);
}
} else if (notification.vibrate.length > 1) {
// If you want your own vibration pattern, you need the VIBRATE permission
mVibrator.vibrate(notification.vibrate,
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
}
} }
} }