lineage-sdk internal: Add LineageNotificationLights

Migrate frameworks/base lineage feature
    code handling to lineage-sdk.

    *) Settings observation and most lineage lights
       feature specific code has been moved to the
       lineage-sdk.

    *) Battery frameworks services call out to the
       sdk to allow our features to make changes to
       lights values.

    Based on the commits:

    Author: DvTonder <david.vantonder@gmail.com>
    Author: Ricardo Cerqueira <cyanogenmod@cerqueira.org>
    Date:   Mon Nov 4 00:57:51 2013 +0000
    Framework: Port CM9 features to CM10
    Change-Id: Ibd63116df90b06f6ce6adb8a0343059bbb999bfb

    Author: Pawit Pornkitprasan <p.pawit@gmail.com>
    Date:   Sun Dec 8 15:24:41 2013 +0700
    BatteryService: fix FC on boot until battery stat is present
    updateLightsLocked() can be called from CM's added SettingsObserver
    when battery stat is not present, causing an FC and a loop until
    battery stat is present.
    Change-Id: Ic4438fe50e98f1aa05ae1d0d26240bf9410fd92f

    Author: Sam Mortimer <sam@mortimer.me.uk>
    Date:   Tue Dec 31 16:22:05 2013 -0800
    [2/2] Framework: instant led test
    Adds support a new notification extra boolean
    EXTRA_FORCE_SHOW_LIGHTS.  Used by settings
    notification light picker to force lights on
    when the screen is on.
    Change-Id: If0a42d32b28fe8c02ef5f7dd148db7eb478fac17

    Author: Michael Bestas <mikeioannina@gmail.com>
    Date:   Mon Aug 18 04:56:28 2014 +0300
    Add support for single color notification LED (1/2)
    Change-Id: I367af77036da9e87c6dd0df552ce4c56d945a44d

    Author: Danesh M <daneshm90@gmail.com>
    Date:   Thu, 12 Nov 2015 10:52:11 -0800
    Framework : Move System settings to CMSettings
    Change-Id: I4e9fb06db7b9ba05e4a7bbe11916bb2271af4727

    Author: Adnan Begovic <adnan@cyngn.com>
    Date:   Mon, 9 Nov 2015 16:26:00 -0800
    fw: Move battery light settings to CMSettings.
    Change-Id: I28e60473356b2a9af152df82d34ad7abc9918682

    Author: Steve Kondik <steve@cyngn.com>
    Date:   Thu Sep 24 11:27:59 2015 -0700
    lights: Automatically generate an LED color for notifications
    Change-Id: I7288e52499819a6a6c75ed9d9ba7cfa1b13c5669
    nms: Only generate LED colors if the device has a multicolored LED
    * Check the overlay value before doing any of this stuff.
    Change-Id: Iedfceba6bfc86b2761d8af57ecab51026bfa4c19
    Change-Id: I7288e52499819a6a6c75ed9d9ba7cfa1b13c5669

    Author: Adrian DC <radian.dc@gmail.com>
    Date:   Sat Oct 14 23:08:47 2017 +0200
    fw: Rebrand to LineageOS and cleanup for Android Oreo
    Change-Id: I21d424433bb52a17eea7974c4ea29a3a16fe1be5

    Author: AdrianDC <radian.dc@gmail.com>
    Date:   Sat Jul 18 12:20:51 2015 +0200
    Lights with Screen On [1/2]: Optional allowment of lights
    Change-Id: I2071147d8ddab80ba0e1e7310e785ac3e03b3c7c
    Lights with screen on: Don't disable leds after the lockscreen
    Change-Id: If8f5b867a34be09fb061bb7ad040b16730f4e263
    Framework : Move System settings to CMSettings
    Change-Id: I4e9fb06db7b9ba05e4a7bbe11916bb2271af4727
    fw: Rebrand to LineageOS and port for Android Oreo
    Change-Id: I65cfeb659fe516ef43aa84b1c6d2eb6876df202a
    Change-Id: If8f5b867a34be09fb061bb7ad040b16730f4e263

    Author: Michael W <baddaemon87@gmail.com>
    Date:   Mon Oct 9 22:04:00 2017 +0200
    Core: Battery warning levels are inclusive, not exclusive
    Change-Id: Ib35b154b6117f7e26b4a3a5aee9254dda3adda12

    Author: Adrian DC <radian.dc@gmail.com>
    Date:   Sat Oct 14 23:08:47 2017 +0200
    fw: Rebrand to LineageOS and cleanup for Android Oreo
    Change-Id: I845f866891386aee808a4e7e80f4ab7c3ad48830

Change-Id: Ic4c9c5f5602515ccbc2c6b8b10bcf3d2c6e34b4b
This commit is contained in:
Sam Mortimer
2017-10-22 14:43:46 -07:00
parent cef20e4e1f
commit fdb387454b
3 changed files with 366 additions and 0 deletions

View File

@@ -108,4 +108,13 @@
<item>@string/accessibility_quick_settings_live_display_changed_outdoor</item>
</string-array>
<!-- LineageNotificationLights -->
<!-- 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>

View File

@@ -118,4 +118,7 @@
<!-- BurnIn protection -->
<java-symbol type="bool" name="config_enableBurnInProtection" />
<!-- Notification light mappings -->
<java-symbol type="array" name="notification_light_package_mapping" />
</resources>

View File

@@ -0,0 +1,354 @@
/**
* Copyright (C) 2015 The CyanogenMod Project
* Copyright (C) 2017 The LineageOS 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.
*/
package org.lineageos.internal.notification;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
import android.app.KeyguardManager;
import android.app.Notification;
import android.content.Context;
import android.content.ContentResolver;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Slog;
import lineageos.providers.LineageSettings;
import lineageos.util.ColorUtils;
import org.lineageos.internal.notification.LedValues;
import org.lineageos.internal.notification.LightsCapabilities;
import java.util.Map;
public final class LineageNotificationLights {
private static final String TAG = "LineageNotificationLights";
private static final boolean DEBUG = false;
// Light capabilities
private boolean mAdjustableNotificationLedBrightness;
private boolean mMultiColorNotificationLed;
// Light config
private boolean mAutoGenerateNotificationColor;
private boolean mScreenOnEnabled;
private int mNotificationLedBrightnessLevel;
private int mDefaultNotificationColor;
private int mDefaultNotificationLedOn;
private int mDefaultNotificationLedOff;
private ArrayMap<String, LedValues> mNotificationPulseCustomLedValues;
private Map<String, String> mPackageNameMappings;
private final ArrayMap<String, Integer> mGeneratedPackageLedColors =
new ArrayMap<String, Integer>();
// For checking lockscreen status
private KeyguardManager mKeyguardManager;
private final SettingsObserver mSettingsObserver;
private final Context mContext;
public interface LedUpdater {
public void update();
}
private final LedUpdater mLedUpdater;
public LineageNotificationLights(Context context, LedUpdater ledUpdater) {
mContext = context;
mLedUpdater = ledUpdater;
final Resources res = mContext.getResources();
mAdjustableNotificationLedBrightness = LightsCapabilities.supports(
mContext, LightsCapabilities.LIGHTS_ADJUSTABLE_NOTIFICATION_LED_BRIGHTNESS);
mDefaultNotificationColor = res.getColor(
com.android.internal.R.color.config_defaultNotificationColor);
mDefaultNotificationLedOn = res.getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOn);
mDefaultNotificationLedOff = res.getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOff);
mMultiColorNotificationLed = LightsCapabilities.supports(
mContext, LightsCapabilities.LIGHTS_RGB_NOTIFICATION_LED);
mNotificationPulseCustomLedValues = new ArrayMap<String, LedValues>();
mPackageNameMappings = new ArrayMap<String, String>();
final String[] defaultMapping = res.getStringArray(
org.lineageos.platform.internal.R.array.notification_light_package_mapping);
for (String mapping : defaultMapping) {
String[] map = mapping.split("\\|");
mPackageNameMappings.put(map[0], map[1]);
}
mKeyguardManager =
(KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
mSettingsObserver = new SettingsObserver(new Handler());
mSettingsObserver.observe();
}
// Whether we should show lights if the screen is on.
public boolean showLightsScreenOn() {
return mScreenOnEnabled;
}
// Used by NotificationManagerService to help determine
// when lights should / should not be cleared.
// TODO: put this somewhere else
public boolean isKeyguardLocked() {
return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
}
private void parseNotificationPulseCustomValuesString(String customLedValuesString) {
if (TextUtils.isEmpty(customLedValuesString)) {
return;
}
for (String packageValuesString : customLedValuesString.split("\\|")) {
String[] packageValues = packageValuesString.split("=");
if (packageValues.length != 2) {
Slog.e(TAG, "Error parsing custom led values for unknown package");
continue;
}
String packageName = packageValues[0];
String[] values = packageValues[1].split(";");
if (values.length != 3) {
Slog.e(TAG, "Error parsing custom led values '"
+ packageValues[1] + "' for " + packageName);
continue;
}
LedValues ledValues;
try {
// color, onMs, offMs
ledValues = new LedValues(Integer.parseInt(values[0]),
Integer.parseInt(values[1]), Integer.parseInt(values[2]));
} catch (NumberFormatException e) {
Slog.e(TAG, "Error parsing custom led values '"
+ packageValues[1] + "' for " + packageName);
continue;
}
mNotificationPulseCustomLedValues.put(packageName, ledValues);
}
}
private LedValues getLedValuesForPackageName(String packageName) {
return mNotificationPulseCustomLedValues.get(mapPackage(packageName));
}
private int generateLedColorForPackageName(String packageName) {
if (!mAutoGenerateNotificationColor) {
return mDefaultNotificationColor;
}
if (!mMultiColorNotificationLed) {
return mDefaultNotificationColor;
}
final String mapping = mapPackage(packageName);
int color = mDefaultNotificationColor;
if (mGeneratedPackageLedColors.containsKey(mapping)) {
return mGeneratedPackageLedColors.get(mapping);
}
PackageManager pm = mContext.getPackageManager();
Drawable icon;
try {
icon = pm.getApplicationIcon(mapping);
} catch (NameNotFoundException e) {
Slog.e(TAG, e.getMessage(), e);
return color;
}
color = ColorUtils.generateAlertColorFromDrawable(icon);
mGeneratedPackageLedColors.put(mapping, color);
return color;
}
private String mapPackage(String pkg) {
if (!mPackageNameMappings.containsKey(pkg)) {
return pkg;
}
return mPackageNameMappings.get(pkg);
}
// Called by NotificationManagerService updateLightsLocked().
// Takes the lights values as requested by a notification and
// updates them according to the active Lineage feature settings.
public void calcLights(LedValues ledValues, String packageName, boolean forcedOn,
boolean screenOn, boolean inCall, boolean isDefaultLights, int suppressedEffects) {
if (DEBUG) {
Slog.i(TAG, "calcLights input: ledValues={ " + ledValues + " } packageName="
+ packageName + " forcedOn=" + forcedOn + " screenOn=" + screenOn
+ " inCall=" + inCall + " isDefaultLights=" + isDefaultLights
+ " suppressedEffects=" + suppressedEffects);
}
final boolean suppressScreenOff =
(suppressedEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0;
final boolean suppressScreenOn =
(suppressedEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0;
final boolean screenActive = screenOn || inCall;
final boolean enableLed;
if (forcedOn) {
// Forced on always enables
enableLed = true;
} else if (screenActive && (!mScreenOnEnabled || suppressScreenOn)) {
// Screen on cases where we disable
enableLed = false;
} else if (!screenActive && suppressScreenOff) {
// Screen off cases where we disable
enableLed = false;
} else {
// Enable by default fallthrough
enableLed = true;
}
if (!enableLed) {
ledValues.setEnabled(false);
return;
}
ledValues.setBrightness(mAdjustableNotificationLedBrightness ?
mNotificationLedBrightnessLevel : LedValues.LIGHT_BRIGHTNESS_MAXIMUM);
final LedValues ledValuesPkg = getLedValuesForPackageName(packageName);
// Use package specific values that the user has chosen.
if (ledValuesPkg != null) {
ledValues.setColor(ledValuesPkg.getColor() != 0 ?
ledValuesPkg.getColor() : generateLedColorForPackageName(packageName));
ledValues.setOnMs(ledValuesPkg.getOnMs() >= 0 ?
ledValuesPkg.getOnMs() : mDefaultNotificationLedOn);
ledValues.setOffMs(ledValuesPkg.getOffMs() >= 0 ?
ledValuesPkg.getOffMs() : mDefaultNotificationLedOff);
} else if (isDefaultLights) {
ledValues.setColor(generateLedColorForPackageName(packageName));
ledValues.setOnMs(mDefaultNotificationLedOn);
ledValues.setOffMs(mDefaultNotificationLedOff);
}
if (DEBUG) {
Slog.i(TAG, "calcLights output: ledValues={ " + ledValues + " }");
}
}
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
}
void observe() {
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_SCREEN_ON),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_COLOR_AUTO), false,
this, UserHandle.USER_ALL);
if (mAdjustableNotificationLedBrightness) {
resolver.registerContentObserver(LineageSettings.System.getUriFor(
LineageSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL),
false, this, UserHandle.USER_ALL);
}
update();
}
@Override
public void onChange(boolean selfChange) {
update();
}
private void update() {
ContentResolver resolver = mContext.getContentResolver();
Resources res = mContext.getResources();
// Automatically pick a color for LED if not set
mAutoGenerateNotificationColor = LineageSettings.System.getIntForUser(resolver,
LineageSettings.System.NOTIFICATION_LIGHT_COLOR_AUTO,
1, UserHandle.USER_CURRENT) != 0;
// LED default color
mDefaultNotificationColor = LineageSettings.System.getIntForUser(resolver,
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR,
mDefaultNotificationColor, UserHandle.USER_CURRENT);
// LED default on MS
mDefaultNotificationLedOn = LineageSettings.System.getIntForUser(resolver,
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON,
mDefaultNotificationLedOn, UserHandle.USER_CURRENT);
// LED default off MS
mDefaultNotificationLedOff = LineageSettings.System.getIntForUser(resolver,
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF,
mDefaultNotificationLedOff, UserHandle.USER_CURRENT);
// LED generated notification colors
mGeneratedPackageLedColors.clear();
// LED custom notification colors
mNotificationPulseCustomLedValues.clear();
if (LineageSettings.System.getIntForUser(resolver,
LineageSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE, 0,
UserHandle.USER_CURRENT) != 0) {
parseNotificationPulseCustomValuesString(LineageSettings.System.getStringForUser(
resolver, LineageSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES,
UserHandle.USER_CURRENT));
}
// Notification LED brightness
if (mAdjustableNotificationLedBrightness) {
mNotificationLedBrightnessLevel = LineageSettings.System.getIntForUser(resolver,
LineageSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
LedValues.LIGHT_BRIGHTNESS_MAXIMUM, UserHandle.USER_CURRENT);
}
// Notification lights with screen on
mScreenOnEnabled = (LineageSettings.System.getIntForUser(resolver,
LineageSettings.System.NOTIFICATION_LIGHT_SCREEN_ON, 0,
UserHandle.USER_CURRENT) != 0);
mLedUpdater.update();
}
}
}