summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Notification.java7
-rw-r--r--core/java/android/preference/DialogPreference.java29
-rw-r--r--core/java/android/provider/Settings.java108
-rw-r--r--core/res/res/values/cm_arrays.xml26
-rwxr-xr-xcore/res/res/values/config.xml21
-rwxr-xr-xcore/res/res/values/symbols.xml9
-rw-r--r--services/core/java/com/android/server/BatteryService.java117
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java193
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)
{