summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/NotificationManagerService.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/NotificationManagerService.java')
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java256
1 files changed, 234 insertions, 22 deletions
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index f3a38f0..af49135 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -27,7 +27,12 @@ import android.app.IActivityManager;
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.Notification;
+import android.app.NotificationGroup;
+import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.Profile;
+import android.app.ProfileGroup;
+import android.app.ProfileManager;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -44,6 +49,7 @@ import android.media.IAudioService;
import android.media.IRingtonePlayer;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -81,7 +87,10 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Calendar;
+import java.util.Map;
import libcore.io.IoUtils;
@@ -134,10 +143,13 @@ public class NotificationManagerService extends INotificationManager.Stub
private IAudioService mAudioService;
private Vibrator mVibrator;
- // for enabling and disabling notification pulse behavior
+ // for enabling and disabling notification pulse behaviour
private boolean mScreenOn = true;
+ private boolean mWasScreenOn = false;
private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
+ private HashMap<String, NotificationLedValues> mNotificationPulseCustomLedValues;
+ private Map<String, String> mPackageNameMappings;
private final ArrayList<NotificationRecord> mNotificationList =
new ArrayList<NotificationRecord>();
@@ -147,6 +159,18 @@ public class NotificationManagerService extends INotificationManager.Stub
private ArrayList<NotificationRecord> mLights = new ArrayList<NotificationRecord>();
private NotificationRecord mLedNotification;
+ private boolean mQuietHoursEnabled = false;
+ // Minutes from midnight when quiet hours begin.
+ private int mQuietHoursStart = 0;
+ // Minutes from midnight when quiet hours end.
+ private int mQuietHoursEnd = 0;
+ // Don't play sounds.
+ private boolean mQuietHoursMute = true;
+ // Don't vibrate.
+ private boolean mQuietHoursStill = true;
+ // Dim LED if hardware supports it.
+ private boolean mQuietHoursDim = true;
+
// Notification control database. For now just contains disabled packages.
private AtomicFile mPolicyFile;
private HashSet<String> mBlockedPackages = new HashSet<String>();
@@ -402,6 +426,12 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ class NotificationLedValues {
+ public int color;
+ public int onMS;
+ public int offMS;
+ }
+
private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
= new StatusBarManagerService.NotificationCallbacks() {
@@ -553,6 +583,8 @@ public class NotificationManagerService extends INotificationManager.Stub
mScreenOn = true;
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
+ mWasScreenOn = true;
+ updateLightsLocked();
} else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK));
@@ -569,8 +601,8 @@ public class NotificationManagerService extends INotificationManager.Stub
}
};
- class SettingsObserver extends ContentObserver {
- SettingsObserver(Handler handler) {
+ class LEDSettingsObserver extends ContentObserver {
+ LEDSettingsObserver(Handler handler) {
super(handler);
}
@@ -578,24 +610,96 @@ public class NotificationManagerService extends INotificationManager.Stub
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.NOTIFICATION_LIGHT_PULSE), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES), false, this);
update();
}
@Override public void onChange(boolean selfChange) {
update();
+ updateNotificationPulse();
}
public void update() {
ContentResolver resolver = mContext.getContentResolver();
- boolean pulseEnabled = Settings.System.getInt(resolver,
- Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
- if (mNotificationPulseEnabled != pulseEnabled) {
- mNotificationPulseEnabled = pulseEnabled;
- updateNotificationPulse();
+ // LED enabled
+ mNotificationPulseEnabled = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
+
+ // LED default color
+ mDefaultNotificationColor = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR, mDefaultNotificationColor);
+
+ // LED default on MS
+ mDefaultNotificationLedOn = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON, mDefaultNotificationLedOn);
+
+ // LED default off MS
+ mDefaultNotificationLedOff = Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF, mDefaultNotificationLedOff);
+
+ // LED custom notification colors
+ mNotificationPulseCustomLedValues.clear();
+ if (Settings.System.getInt(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE, 0) != 0) {
+ parseNotificationPulseCustomValuesString(Settings.System.getString(resolver,
+ Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES));
}
}
}
+ class QuietHoursSettingsObserver extends ContentObserver {
+ QuietHoursSettingsObserver(Handler handler) {
+ super(handler);
+ }
+
+ void observe() {
+ ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_ENABLED), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_START), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_END), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_MUTE), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_STILL), false, this);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.QUIET_HOURS_DIM), false, this);
+ update();
+ }
+
+ @Override public void onChange(boolean selfChange) {
+ update();
+ updateNotificationPulse();
+ }
+
+ public void update() {
+ ContentResolver resolver = mContext.getContentResolver();
+ mQuietHoursEnabled = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_ENABLED, 0) != 0;
+ mQuietHoursStart = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_START, 0);
+ mQuietHoursEnd = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_END, 0);
+ mQuietHoursMute = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_MUTE, 0) != 0;
+ mQuietHoursStill = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_STILL, 0) != 0;
+ mQuietHoursDim = Settings.System.getInt(resolver,
+ Settings.System.QUIET_HOURS_DIM, 0) != 0;
+ }
+ }
+
NotificationManagerService(Context context, StatusBarManagerService statusBar,
LightsService lights)
{
@@ -622,6 +726,15 @@ public class NotificationManagerService extends INotificationManager.Stub
mDefaultNotificationLedOff = resources.getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOff);
+ mNotificationPulseCustomLedValues = new HashMap<String, NotificationLedValues>();
+
+ mPackageNameMappings = new HashMap<String, String>();
+ for(String mapping : resources.getStringArray(
+ com.android.internal.R.array.notification_light_package_mapping)) {
+ String[] map = mapping.split("\\|");
+ mPackageNameMappings.put(map[0], map[1]);
+ }
+
// Don't start allowing notifications until the setup wizard has run once.
// After that, including subsequent boots, init with notifications turned on.
// This works on the first boot because the setup wizard will toggle this
@@ -649,8 +762,10 @@ public class NotificationManagerService extends INotificationManager.Stub
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
mContext.registerReceiver(mIntentReceiver, sdFilter);
- SettingsObserver observer = new SettingsObserver(mHandler);
- observer.observe();
+ LEDSettingsObserver ledObserver = new LEDSettingsObserver(mHandler);
+ ledObserver.observe();
+ QuietHoursSettingsObserver qhObserver = new QuietHoursSettingsObserver(mHandler);
+ qhObserver.observe();
}
void systemReady() {
@@ -965,6 +1080,8 @@ public class NotificationManagerService extends INotificationManager.Stub
}
synchronized (mNotificationList) {
+ final boolean inQuietHours = inQuietHours();
+
NotificationRecord r = new NotificationRecord(pkg, tag, id,
callingUid, callingPid, userId,
score,
@@ -1040,6 +1157,16 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ try {
+ final ProfileManager profileManager =
+ (ProfileManager) mContext.getSystemService(Context.PROFILE_SERVICE);
+
+ ProfileGroup group = profileManager.getActiveProfileGroup(pkg);
+ notification = group.processNotification(notification);
+ } catch(Throwable th) {
+ Log.e(TAG, "An error occurred profiling the notification.", th);
+ }
+
// If we're not supposed to beep, vibrate, etc. then don't.
if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
&& (!(old != null
@@ -1053,7 +1180,8 @@ public class NotificationManagerService extends INotificationManager.Stub
// sound
final boolean useDefaultSound =
(notification.defaults & Notification.DEFAULT_SOUND) != 0;
- if (useDefaultSound || notification.sound != null) {
+ if (!(inQuietHours && mQuietHoursMute)
+ && (useDefaultSound || notification.sound != null)) {
Uri uri;
if (useDefaultSound) {
uri = Settings.System.DEFAULT_NOTIFICATION_URI;
@@ -1096,8 +1224,8 @@ public class NotificationManagerService extends INotificationManager.Stub
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0
|| convertSoundToVibration;
-
- if ((useDefaultVibrate || notification.vibrate != null)
+ if (!(inQuietHours && mQuietHoursStill)
+ && (useDefaultVibrate || notification.vibrate != null)
&& !(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) {
mVibrateNotification = r;
@@ -1131,6 +1259,21 @@ public class NotificationManagerService extends INotificationManager.Stub
idOut[0] = id;
}
+ private boolean inQuietHours() {
+ if (mQuietHoursEnabled && (mQuietHoursStart != mQuietHoursEnd)) {
+ // Get the date in "quiet hours" format.
+ Calendar calendar = Calendar.getInstance();
+ int minutes = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE);
+ if (mQuietHoursEnd < mQuietHoursStart) {
+ // Starts at night, ends in the morning.
+ return (minutes > mQuietHoursStart) || (minutes < mQuietHoursEnd);
+ } else {
+ return (minutes > mQuietHoursStart) && (minutes < mQuietHoursEnd);
+ }
+ }
+ return false;
+ }
+
private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
if (!manager.isEnabled()) {
@@ -1376,17 +1519,45 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
- // Don't flash while we are in a call or screen is on
- if (mLedNotification == null || mInCall || mScreenOn) {
+ boolean wasScreenOn = mWasScreenOn;
+ mWasScreenOn = false;
+
+ if (mLedNotification == null) {
+ mNotificationLight.turnOff();
+ return;
+ }
+
+ // We can assume that if the user turned the screen off while there was
+ // still an active notification then they wanted to keep the notification
+ // for later. In this case we shouldn't flash the notification light.
+ // For special notifications that automatically turn the screen on (such
+ // as missed calls), we use this flag to force the notification light
+ // even if the screen was turned off.
+ boolean forceWithScreenOff = (mLedNotification.notification.flags &
+ Notification.FLAG_FORCE_LED_SCREEN_OFF) != 0;
+
+ // Don't flash while we are in a call, screen is on or we are in quiet hours with light dimmed
+ if (mInCall || mScreenOn || (inQuietHours() && mQuietHoursDim) || (wasScreenOn && !forceWithScreenOff)) {
mNotificationLight.turnOff();
} else {
- int ledARGB = mLedNotification.notification.ledARGB;
- int ledOnMS = mLedNotification.notification.ledOnMS;
- int ledOffMS = mLedNotification.notification.ledOffMS;
- if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
- ledARGB = mDefaultNotificationColor;
- ledOnMS = mDefaultNotificationLedOn;
- ledOffMS = mDefaultNotificationLedOff;
+ int ledARGB;
+ int ledOnMS;
+ int ledOffMS;
+ NotificationLedValues ledValues = getLedValuesForNotification(mLedNotification);
+ if (ledValues != null) {
+ ledARGB = ledValues.color != 0 ? ledValues.color : mDefaultNotificationColor;
+ ledOnMS = ledValues.onMS >= 0 ? ledValues.onMS : mDefaultNotificationLedOn;
+ ledOffMS = ledValues.offMS >= 0 ? ledValues.offMS : mDefaultNotificationLedOn;
+ } else {
+ if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
+ ledARGB = mDefaultNotificationColor;
+ ledOnMS = mDefaultNotificationLedOn;
+ ledOffMS = mDefaultNotificationLedOff;
+ } else {
+ ledARGB = mLedNotification.notification.ledARGB;
+ ledOnMS = mLedNotification.notification.ledOnMS;
+ ledOffMS = mLedNotification.notification.ledOffMS;
+ }
}
if (mNotificationPulseEnabled) {
// pulse repeatedly
@@ -1396,6 +1567,47 @@ public class NotificationManagerService extends INotificationManager.Stub
}
}
+ private void parseNotificationPulseCustomValuesString(String customLedValuesString) {
+ if (TextUtils.isEmpty(customLedValuesString)) {
+ return;
+ }
+
+ for (String packageValuesString : customLedValuesString.split("\\|")) {
+ String[] packageValues = packageValuesString.split("=");
+ if (packageValues.length != 2) {
+ Log.e(TAG, "Error parsing custom led values for unknown package");
+ continue;
+ }
+ String packageName = packageValues[0];
+ String[] values = packageValues[1].split(";");
+ if (values.length != 3) {
+ Log.e(TAG, "Error parsing custom led values '" + packageValues[1] + "' for " + packageName);
+ continue;
+ }
+ NotificationLedValues ledValues = new NotificationLedValues();
+ try {
+ ledValues.color = Integer.parseInt(values[0]);
+ ledValues.onMS = Integer.parseInt(values[1]);
+ ledValues.offMS = Integer.parseInt(values[2]);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing custom led values '" + packageValues[1] + "' for " + packageName);
+ continue;
+ }
+ mNotificationPulseCustomLedValues.put(packageName, ledValues);
+ }
+ }
+
+ private NotificationLedValues getLedValuesForNotification(NotificationRecord ledNotification) {
+ return mNotificationPulseCustomLedValues.get(mapPackage(ledNotification.pkg));
+ }
+
+ private String mapPackage(String pkg) {
+ if(!mPackageNameMappings.containsKey(pkg)) {
+ return pkg;
+ }
+ return mPackageNameMappings.get(pkg);
+ }
+
// lock on mNotificationList
private int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
{