Skip to content

Commit

Permalink
Notification LED Control (1/2).
Browse files Browse the repository at this point in the history
[Original writen at CyanogenMod by David Van Tonder (DvTonder <david.vantonder@gmail.com>).]

* Make led color customizable.
* Global and per-app settings.
* Default led color is white.
* The option category replace old stock on/off checkbox.
* Remove useless code from display settings, the feature has its own java files.
* The java files in settings are stored into its own com/android/settings/notificationligh folder.
* Credits into code comments of each specific java file.

PS2/3/4:

* Fix code derps.
* Forget to define a method.
* Remove wrongly added code.

PS5/6:

* Move entries to pa_symbols and pa_config.
* Update description.

PS7:

* Use ArrayMap instead of HashMap (more memory efficient).
* Remove observer for medium battery level.

PS8:

* Correctly import ArrayMap.
* Didn't updated creating of ArrayMaps.

PS9/10:

* Fix defaults.
* Enable battery led.
* Update description.

PS11/12:

* Ditch battery led option.
* Update commit description.

Signed-off-by: Carlo Savignano <stevewatersy@gmail.com>

Change-Id: I34654992e0225c32413e6cbe9f0ca18c1729a186
  • Loading branch information
kaluoshi committed Nov 19, 2013
1 parent ff0568b commit 4711488
Show file tree
Hide file tree
Showing 4 changed files with 185 additions and 9 deletions.
66 changes: 66 additions & 0 deletions core/java/android/provider/Settings.java
Expand Up @@ -2252,6 +2252,72 @@ public static void setShowGTalkServiceStatusForUser(ContentResolver cr, boolean
*/
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";

/**
* 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";

/**
* Show pointer location on screen?
* 0 = no
Expand Down
8 changes: 8 additions & 0 deletions core/res/res/values/pa_arrays.xml
Expand Up @@ -40,4 +40,12 @@
<item>@drawable/ic_lock_reboot_bootloader</item>
</array>

<!-- 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>
5 changes: 4 additions & 1 deletion core/res/res/values/pa_symbols.xml
Expand Up @@ -16,7 +16,7 @@
*/
-->
<resources>
<!-- From power menu -->
<!--From power menu-->
<java-symbol type="array" name="shutdown_reboot_options" />
<java-symbol type="array" name="shutdown_reboot_actions" />
<java-symbol type="array" name="shutdown_reboot_icons" />
Expand All @@ -29,4 +29,7 @@
<java-symbol type="string" name="global_action_screenshot" />
<java-symbol type="string" name="reboot_confirm" />
<java-symbol type="string" name="reboot_progress" />

<!--Notification led-->
<java-symbol type="array" name="notification_light_package_mapping" />
</resources>
115 changes: 107 additions & 8 deletions services/java/com/android/server/NotificationManagerService.java
Expand Up @@ -28,6 +28,7 @@
import android.app.INotificationManager;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
Expand All @@ -51,6 +52,7 @@
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;
Expand All @@ -66,6 +68,7 @@
import android.service.notification.StatusBarNotification;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.Log;
Expand Down Expand Up @@ -94,6 +97,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

Expand Down Expand Up @@ -162,8 +166,11 @@ public class NotificationManagerService extends INotificationManager.Stub

// for enabling and disabling notification pulse behavior
private boolean mScreenOn = true;
private boolean mWasScreenOn = true;
private boolean mInCall = false;
private boolean mNotificationPulseEnabled;
private ArrayMap<String, NotificationLedValues> mNotificationPulseCustomLedValues;
private Map<String, String> mPackageNameMappings;

// used as a mutex for access to all active notifications & listeners
private final ArrayList<NotificationRecord> mNotificationList =
Expand Down Expand Up @@ -1031,6 +1038,12 @@ public final String toString()
}
}

class NotificationLedValues {
public int color;
public int onMS;
public int offMS;
}

private StatusBarManagerService.NotificationCallbacks mNotificationCallbacks
= new StatusBarManagerService.NotificationCallbacks() {

Expand Down Expand Up @@ -1213,6 +1226,8 @@ public void onReceive(Context context, Intent intent) {
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));
Expand Down Expand Up @@ -1249,22 +1264,48 @@ void observe() {
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);
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(null);
}

@Override public void onChange(boolean selfChange, Uri uri) {
update(uri);
updateNotificationPulse();
}

public void update(Uri uri) {
ContentResolver resolver = mContext.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));
}
if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) {
rebindListenerServices();
Expand Down Expand Up @@ -1326,6 +1367,15 @@ static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
VIBRATE_PATTERN_MAXLEN,
DEFAULT_VIBRATE_PATTERN);

mNotificationPulseCustomLedValues = new ArrayMap<String, NotificationLedValues>();

mPackageNameMappings = new ArrayMap<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
Expand Down Expand Up @@ -2241,10 +2291,15 @@ private void updateLightsLocked()
mNotificationLight.turnOff();
} else {
final Notification ledno = mLedNotification.sbn.getNotification();
final NotificationLedValues ledValues = getLedValuesForNotification(mLedNotification);
int ledARGB = ledno.ledARGB;
int ledOnMS = ledno.ledOnMS;
int ledOffMS = ledno.ledOffMS;
if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
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;
Expand All @@ -2257,6 +2312,50 @@ private void updateLightsLocked()
}
}

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) {
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
private int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
{
Expand Down

0 comments on commit 4711488

Please sign in to comment.