diff options
-rw-r--r-- | core/java/android/app/Notification.java | 7 | ||||
-rw-r--r-- | core/java/android/preference/DialogPreference.java | 29 | ||||
-rw-r--r-- | core/java/android/provider/Settings.java | 108 | ||||
-rw-r--r-- | core/res/res/values/cm_arrays.xml | 26 | ||||
-rwxr-xr-x | core/res/res/values/config.xml | 21 | ||||
-rwxr-xr-x | core/res/res/values/symbols.xml | 9 | ||||
-rw-r--r-- | services/core/java/com/android/server/BatteryService.java | 117 | ||||
-rw-r--r-- | services/core/java/com/android/server/notification/NotificationManagerService.java | 193 |
8 files changed, 463 insertions, 47 deletions
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index f3f2428..5c5562d 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -895,6 +895,13 @@ public class Notification implements Parcelable private Icon mLargeIcon; /** + * Used by light picker in Settings to force + * notification lights on when screen is on + * @hide + */ + public static final String EXTRA_FORCE_SHOW_LIGHTS = "android.forceShowLights"; + + /** * Structure to encapsulate a named action that can be shown as part of this notification. * It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is * selected by the user. diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java index 3d57b4d..1aec3ec 100644 --- a/core/java/android/preference/DialogPreference.java +++ b/core/java/android/preference/DialogPreference.java @@ -285,6 +285,22 @@ public abstract class DialogPreference extends Preference implements * @param state Optional instance state to restore on the dialog */ protected void showDialog(Bundle state) { + // Create the dialog + final Dialog dialog = mDialog = createDialog(); + if (state != null) { + dialog.onRestoreInstanceState(state); + } + if (needInputMethod()) { + requestInputMethod(dialog); + } + dialog.setOnDismissListener(this); + dialog.show(); + } + + /** + * @hide + */ + protected Dialog createDialog() { Context context = getContext(); mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE; @@ -306,17 +322,8 @@ public abstract class DialogPreference extends Preference implements onPrepareDialogBuilder(mBuilder); getPreferenceManager().registerOnActivityDestroyListener(this); - - // Create the dialog - final Dialog dialog = mDialog = mBuilder.create(); - if (state != null) { - dialog.onRestoreInstanceState(state); - } - if (needInputMethod()) { - requestInputMethod(dialog); - } - dialog.setOnDismissListener(this); - dialog.show(); + + return mBuilder.create(); } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5430589..d5d54ab 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3032,6 +3032,114 @@ public final class Settings { public static final Validator NOTIFICATION_LIGHT_PULSE_VALIDATOR = sBooleanValidator; /** + * What color to use for the notification LED by default + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR = + "notification_light_pulse_default_color"; + + /** + * How long to flash the notification LED by default + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON = + "notification_light_pulse_default_led_on"; + + /** + * How long to wait between flashes for the notification LED by default + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF = + "notification_light_pulse_default_led_off"; + + /** + * What color to use for the missed call notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CALL_COLOR = + "notification_light_pulse_call_color"; + + /** + * How long to flash the missed call notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CALL_LED_ON = + "notification_light_pulse_call_led_on"; + + /** + * How long to wait between flashes for the missed call notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CALL_LED_OFF = + "notification_light_pulse_call_led_off"; + /** + * What color to use for the voicemail notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_COLOR = + "notification_light_pulse_vmail_color"; + + /** + * How long to flash the voicemail notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_LED_ON = + "notification_light_pulse_vmail_led_on"; + + /** + * How long to wait between flashes for the voicemail notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_LED_OFF = + "notification_light_pulse_vmail_led_off"; + + /** + * Whether to use the custom LED values for the notification pulse LED. + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE = + "notification_light_pulse_custom_enable"; + + /** + * Which custom LED values to use for the notification pulse LED. + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES = + "notification_light_pulse_custom_values"; + + /** + * Whether the battery light should be enabled (if hardware supports it) + * The value is boolean (1 or 0). + * @hide + */ + public static final String BATTERY_LIGHT_ENABLED = "battery_light_enabled"; + + /** + * Whether the battery LED should repeatedly flash when the battery is low + * on charge. The value is boolean (1 or 0). + * @hide + */ + public static final String BATTERY_LIGHT_PULSE = "battery_light_pulse"; + + /** + * What color to use for the battery LED while charging - low + * @hide + */ + public static final String BATTERY_LIGHT_LOW_COLOR = "battery_light_low_color"; + + /** + * What color to use for the battery LED while charging - medium + * @hide + */ + public static final String BATTERY_LIGHT_MEDIUM_COLOR = "battery_light_medium_color"; + + /** + * What color to use for the battery LED while charging - full + * @hide + */ + public static final String BATTERY_LIGHT_FULL_COLOR = "battery_light_full_color"; + + /** * Show pointer location on screen? * 0 = no * 1 = yes diff --git a/core/res/res/values/cm_arrays.xml b/core/res/res/values/cm_arrays.xml new file mode 100644 index 0000000..aeb1e7f --- /dev/null +++ b/core/res/res/values/cm_arrays.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2013-2014 The CyanogenMod Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Do not translate. Defines the mapping of notification package names + from the actual triggering package to the user selectable package. + E.g. GTalk notifications come via Google Services Framework + Format: [triggering package]|[user package] --> + <string-array name="notification_light_package_mapping" translatable="false"> + <item>com.google.android.gsf|com.google.android.talk</item> + </string-array> + +</resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3d6c8ce..08ca823 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -878,6 +878,17 @@ <!-- Is the notification LED intrusive? Used to decide if there should be a disable option --> <bool name="config_intrusiveNotificationLed">false</bool> + <!-- Does the notification LED support multiple colors? + Used to decide if the user can change the colors --> + <bool name="config_multiColorNotificationLed">false</bool> + + <!-- Is the battery LED intrusive? Used to decide if there should be a disable option --> + <bool name="config_intrusiveBatteryLed">false</bool> + + <!-- Does the battery LED support multiple colors? + Used to decide if the user can change the colors --> + <bool name="config_multiColorBatteryLed">false</bool> + <!-- Default value for LED off time when the battery is low on charge in miliseconds --> <integer name="config_notificationsBatteryLedOff">2875</integer> @@ -1840,6 +1851,16 @@ <item>100</item> </integer-array> + <!-- Vibrator pattern to be used as for notifications while alerts + are disabled (e.g. during phone calls) if enabled by the user. + --> + <integer-array name="config_notificationNoAlertsVibePattern"> + <item>0</item> + <item>50</item> + <item>100</item> + <item>50</item> + </integer-array> + <!-- Flag indicating if the speed up audio on mt call code should be executed --> <bool name="config_speed_up_audio_on_mt_calls">false</bool> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 06de01f..a281e67 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2381,4 +2381,13 @@ <!-- Gesture Sensor --> <java-symbol type="bool" name="config_enableGestureService" /> + + <!-- Notification and battery light --> + <java-symbol type="bool" name="config_intrusiveNotificationLed" /> + <java-symbol type="bool" name="config_multiColorNotificationLed" /> + <java-symbol type="bool" name="config_intrusiveBatteryLed" /> + <java-symbol type="bool" name="config_multiColorBatteryLed" /> + <java-symbol type="array" name="notification_light_package_mapping" /> + <java-symbol type="array" name="config_notificationNoAlertsVibePattern" /> + </resources> diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index c3200fe..99ce60c 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -29,6 +29,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.database.ContentObserver; import android.os.BatteryManager; import android.os.BatteryManagerInternal; import android.os.BatteryProperties; @@ -144,6 +146,13 @@ public final class BatteryService extends SystemService { private boolean mUpdatesStopped; private Led mLed; + // Disable LED until SettingsObserver can be started + private boolean mLightEnabled = false; + private boolean mLedPulseEnabled; + private int mBatteryLowARGB; + private int mBatteryMediumARGB; + private int mBatteryFullARGB; + private boolean mMultiColorLed; private boolean mSentLowBatteryBroadcast = false; @@ -205,6 +214,9 @@ public final class BatteryService extends SystemService { false, obs, UserHandle.USER_ALL); updateBatteryWarningLevelLocked(); } + } else if (phase == PHASE_BOOT_COMPLETED) { + SettingsObserver observer = new SettingsObserver(new Handler()); + observer.observe(); } } @@ -716,24 +728,23 @@ public final class BatteryService extends SystemService { } }; + private synchronized void updateLedPulse() { + mLed.updateLightsLocked(); + } + private final class Led { private final Light mBatteryLight; - private final int mBatteryLowARGB; - private final int mBatteryMediumARGB; - private final int mBatteryFullARGB; private final int mBatteryLedOn; private final int mBatteryLedOff; public Led(Context context, LightsManager lights) { mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY); - mBatteryLowARGB = context.getResources().getInteger( - com.android.internal.R.integer.config_notificationsBatteryLowARGB); - mBatteryMediumARGB = context.getResources().getInteger( - com.android.internal.R.integer.config_notificationsBatteryMediumARGB); - mBatteryFullARGB = context.getResources().getInteger( - com.android.internal.R.integer.config_notificationsBatteryFullARGB); + // Does the Device support changing battery LED colors? + mMultiColorLed = context.getResources().getBoolean( + com.android.internal.R.bool.config_multiColorBatteryLed); + mBatteryLedOn = context.getResources().getInteger( com.android.internal.R.integer.config_notificationsBatteryLedOn); mBatteryLedOff = context.getResources().getInteger( @@ -772,21 +783,33 @@ public final class BatteryService extends SystemService { * Synchronize on BatteryService. */ public void updateLightsLocked() { + // mBatteryProps could be null on startup (called by SettingsObserver) + if (mBatteryProps == null) { + Slog.w(TAG, "updateLightsLocked: mBatteryProps is null; skipping"); + return; + } + final int level = mBatteryProps.batteryLevel; final int status = mBatteryProps.batteryStatus; - if (level < mLowBatteryWarningLevel) { + if (!mLightEnabled) { + // No lights if explicitly disabled + mBatteryLight.turnOff(); + } else if (level < mLowBatteryWarningLevel) { if (status == BatteryManager.BATTERY_STATUS_CHARGING) { - // Solid red when battery is charging + // Battery is charging and low mBatteryLight.setColor(mBatteryLowARGB); - } else { - // Flash red when battery is low and not charging + } else if (mLedPulseEnabled) { + // Battery is low and not charging mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED, mBatteryLedOn, mBatteryLedOff); + } else { + // "Pulse low battery light" is disabled, no lights. + mBatteryLight.turnOff(); } } else if (status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL) { if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) { - // Solid green when full or charging and nearly full + // Battery is full or charging and nearly full mBatteryLight.setColor(mBatteryFullARGB); } else { if (isHvdcpPresent()) { @@ -794,7 +817,7 @@ public final class BatteryService extends SystemService { mBatteryLight.setFlashing(mBatteryMediumARGB, Light.LIGHT_FLASH_TIMED, mBatteryLedOn, mBatteryLedOn); } else { - // Solid orange when charging and halfway full + // Battery is charging and halfway full mBatteryLight.setColor(mBatteryMediumARGB); } } @@ -869,4 +892,68 @@ public final class BatteryService extends SystemService { } } } + + class SettingsObserver extends ContentObserver { + SettingsObserver(Handler handler) { + super(handler); + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + + // Battery light enabled + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.BATTERY_LIGHT_ENABLED), false, this, UserHandle.USER_ALL); + + // Low battery pulse + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.BATTERY_LIGHT_PULSE), false, this, UserHandle.USER_ALL); + + // Light colors + if (mMultiColorLed) { + // Register observer if we have a multi color led + resolver.registerContentObserver( + Settings.System.getUriFor(Settings.System.BATTERY_LIGHT_LOW_COLOR), + false, this, UserHandle.USER_ALL); + resolver.registerContentObserver( + Settings.System.getUriFor(Settings.System.BATTERY_LIGHT_MEDIUM_COLOR), + false, this, UserHandle.USER_ALL); + resolver.registerContentObserver( + Settings.System.getUriFor(Settings.System.BATTERY_LIGHT_FULL_COLOR), + false, this, UserHandle.USER_ALL); + } + + update(); + } + + @Override public void onChange(boolean selfChange) { + update(); + } + + public void update() { + ContentResolver resolver = mContext.getContentResolver(); + Resources res = mContext.getResources(); + + // Battery light enabled + mLightEnabled = Settings.System.getInt(resolver, + Settings.System.BATTERY_LIGHT_ENABLED, 1) != 0; + + // Low battery pulse + mLedPulseEnabled = Settings.System.getInt(resolver, + Settings.System.BATTERY_LIGHT_PULSE, 1) != 0; + + // Light colors + mBatteryLowARGB = Settings.System.getInt(resolver, + Settings.System.BATTERY_LIGHT_LOW_COLOR, res.getInteger( + com.android.internal.R.integer.config_notificationsBatteryLowARGB)); + mBatteryMediumARGB = Settings.System.getInt(resolver, + Settings.System.BATTERY_LIGHT_MEDIUM_COLOR, res.getInteger( + com.android.internal.R.integer.config_notificationsBatteryMediumARGB)); + mBatteryFullARGB = Settings.System.getInt(resolver, + Settings.System.BATTERY_LIGHT_FULL_COLOR, res.getInteger( + com.android.internal.R.integer.config_notificationsBatteryFullARGB)); + + updateLedPulse(); + } + } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index e6fcdf1..da9e883 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -30,6 +30,7 @@ import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.INotificationManager; import android.app.ITransientNotification; +import android.app.KeyguardManager; import android.app.Notification; import android.app.NotificationManager; import android.app.NotificationManager.Policy; @@ -134,8 +135,10 @@ import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashSet; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -235,6 +238,11 @@ public class NotificationManagerService extends SystemService { private boolean mScreenOn = true; private boolean mInCall = false; private boolean mNotificationPulseEnabled; + private HashMap<String, NotificationLedValues> mNotificationPulseCustomLedValues; + private Map<String, String> mPackageNameMappings; + + // for checking lockscreen status + private KeyguardManager mKeyguardManager; // used as a mutex for access to all active notifications & listeners final ArrayList<NotificationRecord> mNotificationList = @@ -487,6 +495,12 @@ public class NotificationManagerService extends SystemService { } } + class NotificationLedValues { + public int color; + public int onMS; + public int offMS; + } + private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() { @Override @@ -610,9 +624,12 @@ public class NotificationManagerService extends SystemService { Binder.restoreCallingIdentity(identity); } - // light - mLights.clear(); - updateLightsLocked(); + // lights + // clear only if lockscreen is not active + if (mKeyguardManager != null && !mKeyguardManager.isKeyguardLocked()) { + mLights.clear(); + updateLightsLocked(); + } } } @@ -794,17 +811,36 @@ public class NotificationManagerService extends SystemService { } }; - private final class SettingsObserver extends ContentObserver { + private final class LEDSettingsObserver extends ContentObserver { private final Uri NOTIFICATION_LIGHT_PULSE_URI = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); + private final Uri ENABLED_NOTIFICATION_LISTENERS_URI + = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); - SettingsObserver(Handler handler) { + LEDSettingsObserver(Handler handler) { super(handler); } void observe() { ContentResolver resolver = getContext().getContentResolver(); - resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, + resolver.registerContentObserver( + NOTIFICATION_LIGHT_PULSE_URI, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver( + ENABLED_NOTIFICATION_LISTENERS_URI, false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR), + false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON), + false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF), + false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE), + false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES), false, this, UserHandle.USER_ALL); update(null); } @@ -815,18 +851,41 @@ public class NotificationManagerService extends SystemService { public void update(Uri uri) { ContentResolver resolver = getContext().getContentResolver(); - if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { - boolean pulseEnabled = Settings.System.getInt(resolver, - Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; - if (mNotificationPulseEnabled != pulseEnabled) { - mNotificationPulseEnabled = pulseEnabled; - updateNotificationPulse(); - } + + // LED enabled + mNotificationPulseEnabled = Settings.System.getIntForUser(resolver, + Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0; + + // LED default color + mDefaultNotificationColor = Settings.System.getIntForUser(resolver, + Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR, + mDefaultNotificationColor, UserHandle.USER_CURRENT); + + // LED default on MS + mDefaultNotificationLedOn = Settings.System.getIntForUser(resolver, + Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON, + mDefaultNotificationLedOn, UserHandle.USER_CURRENT); + + // LED default off MS + mDefaultNotificationLedOff = Settings.System.getIntForUser(resolver, + Settings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF, + mDefaultNotificationLedOff, UserHandle.USER_CURRENT); + + // LED custom notification colors + mNotificationPulseCustomLedValues.clear(); + if (Settings.System.getIntForUser(resolver, + Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE, 0, + UserHandle.USER_CURRENT) != 0) { + parseNotificationPulseCustomValuesString(Settings.System.getStringForUser(resolver, + Settings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES, + UserHandle.USER_CURRENT)); } + + updateNotificationPulse(); } } - private SettingsObserver mSettingsObserver; + private LEDSettingsObserver mSettingsObserver; private ZenModeHelper mZenModeHelper; private final Runnable mBuzzBeepBlinked = new Runnable() { @@ -861,6 +920,8 @@ public class NotificationManagerService extends SystemService { mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE); mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); + mKeyguardManager = + (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE); mHandler = new WorkerHandler(); mRankingThread.start(); @@ -916,6 +977,16 @@ public class NotificationManagerService extends SystemService { mDefaultNotificationLedOff = resources.getInteger( R.integer.config_defaultNotificationLedOff); + mNotificationPulseCustomLedValues = new HashMap<String, NotificationLedValues>(); + + mPackageNameMappings = new HashMap<String, String>(); + final String[] defaultMapping = resources.getStringArray( + com.android.internal.R.array.notification_light_package_mapping); + for (String mapping : defaultMapping) { + String[] map = mapping.split("\\|"); + mPackageNameMappings.put(map[0], map[1]); + } + mDefaultVibrationPattern = getLongArray(resources, R.array.config_defaultNotificationVibePattern, VIBRATE_PATTERN_MAXLEN, @@ -968,7 +1039,8 @@ public class NotificationManagerService extends SystemService { getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null, null); - mSettingsObserver = new SettingsObserver(mHandler); + mSettingsObserver = new LEDSettingsObserver(mHandler); + mSettingsObserver.observe(); mArchive = new Archive(resources.getInteger( R.integer.config_notificationServiceArchiveSize)); @@ -2457,7 +2529,8 @@ public class NotificationManagerService extends SystemService { // light // release the light boolean wasShowLights = mLights.remove(record.getKey()); - if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) { + final boolean aboveThresholdWithLight = aboveThreshold || isLedNotificationForcedOn(record); + if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThresholdWithLight) { mLights.add(record.getKey()); updateLightsLocked(); if (mUseAttentionLight) { @@ -3042,6 +3115,16 @@ public class NotificationManagerService extends SystemService { } } + private boolean isLedNotificationForcedOn(NotificationRecord r) { + if (r != null) { + final Notification n = r.sbn.getNotification(); + if (n.extras != null) { + return n.extras.getBoolean(Notification.EXTRA_FORCE_SHOW_LIGHTS, false); + } + } + return false; + } + // lock on mNotificationList void updateLightsLocked() { @@ -3057,29 +3140,97 @@ public class NotificationManagerService extends SystemService { } // Don't flash while we are in a call or screen is on - if (ledNotification == null || mInCall || mScreenOn) { + // (unless Notification has EXTRA_FORCE_SHOW_LGHTS) + final boolean enableLed; + if (ledNotification == null) { + enableLed = false; + } else if (isLedNotificationForcedOn(ledNotification)) { + enableLed = true; + } else if (mInCall || mScreenOn) { + enableLed = false; + } else { + enableLed = true; + } + + if (!enableLed) { mNotificationLight.turnOff(); mStatusBar.notificationLightOff(); } else { final Notification ledno = ledNotification.sbn.getNotification(); - int ledARGB = ledno.ledARGB; - int ledOnMS = ledno.ledOnMS; - int ledOffMS = ledno.ledOffMS; - if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { + final NotificationLedValues ledValues = getLedValuesForNotification(ledNotification); + int ledARGB; + int ledOnMS; + int ledOffMS; + + if (ledValues != null) { + ledARGB = ledValues.color != 0 ? ledValues.color : mDefaultNotificationColor; + ledOnMS = ledValues.onMS >= 0 ? ledValues.onMS : mDefaultNotificationLedOn; + ledOffMS = ledValues.offMS >= 0 ? ledValues.offMS : mDefaultNotificationLedOff; + } else if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) { ledARGB = mDefaultNotificationColor; ledOnMS = mDefaultNotificationLedOn; ledOffMS = mDefaultNotificationLedOff; + } else { + ledARGB = ledno.ledARGB; + ledOnMS = ledno.ledOnMS; + ledOffMS = ledno.ledOffMS; } + if (mNotificationPulseEnabled) { // pulse repeatedly mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED, ledOnMS, ledOffMS); } + // let SystemUI make an independent decision mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS); } } + 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 (NumberFormatException e) { + Log.e(TAG, "Error parsing custom led values '" + + packageValues[1] + "' for " + packageName); + continue; + } + mNotificationPulseCustomLedValues.put(packageName, ledValues); + } + } + + private NotificationLedValues getLedValuesForNotification(NotificationRecord ledNotification) { + final String packageName = ledNotification.sbn.getPackageName(); + return mNotificationPulseCustomLedValues.get(mapPackage(packageName)); + } + + private String mapPackage(String pkg) { + if (!mPackageNameMappings.containsKey(pkg)) { + return pkg; + } + return mPackageNameMappings.get(pkg); + } + // lock on mNotificationList int indexOfNotificationLocked(String pkg, String tag, int id, int userId) { |