diff options
Diffstat (limited to 'services/java/com/android/server/NotificationManagerService.java')
-rwxr-xr-x | services/java/com/android/server/NotificationManagerService.java | 256 |
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) { |