伪原创,网络整理,作为自己学习的记录:
原文http://bbs.9ria.com/thread-262894-1-7.html
Android中有各种灯,背光灯,按键灯,指示灯,等等;前几天修改了这部分代码,整理下思路,其实都不难;
首先,来说说指示灯(提示灯),即未接电话,未接短信的时候,会闪灯,这个其实就是NotificationManager这个类中的notify()方法来处理的;流程简单来过一下:
Step 1:从应用层发送的notify(),到framework层被NotificationManager.java这个类接受了,来看看这个notify()这个方法:
java代码
-
public void notify(int id, Notification notification)
-
-
{
-
notify(null, id, notification);
- }
-
public void notify(String tag, int id, Notification
-
notification)
-
-
{
-
int[] idOut = new int[1];
-
INotificationManager service = getService();
-
String pkg = mContext.getPackageName();
-
if (notification.sound != null) {
-
notification.sound = notification.sound.getCanonicalUri();
-
}
-
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification +
-
")");
-
try {
-
service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
-
UserHandle.myUserId());
-
if (id != idOut[0]) {
-
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " +
-
idOut[0]);
-
}
-
} catch (RemoteException e) {
-
}
- }
Step 2:enqueueNotificationWithTag()这个方法调用到了NotificationManagerService.java这个类中去了,来看看这个方法:
java代码
-
public void enqueueNotificationWithTag(String pkg, String
-
tag, int id, Notification notification,
-
-
int[] idOut, int userId)
-
{
-
enqueueNotificationInternal(pkg, Binder.getCallingUid(),
-
Binder.getCallingPid(),
-
tag, id, notification, idOut, userId);
- }
// Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
-
// uid/pid of another application)
-
public void enqueueNotificationInternal(String pkg, int callingUid, int
-
callingPid,
-
String tag, int id, Notification notification, int[] idOut, int userId)
-
{
-
if (DBG) {
-
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + "
-
notification=" + notification + ", notification.ledARGB : "+
-
notification.ledARGB);
-
}
-
checkCallerIsSystemOrSameApp(pkg);
-
final boolean isSystemNotification = ("android".equals(pkg));
-
userId = ActivityManager.handleIncomingUser(callingPid,
-
callingUid, userId, true, false, "enqueueNotification", pkg);
-
UserHandle user = new UserHandle(userId);
-
// Limit the number of notifications that any given package except the
-
android
-
// package can enqueue. Prevents DOS attacks and deals with leaks.
-
if (!isSystemNotification) {
-
synchronized (mNotificationList) {
-
int count = 0;
-
int eldestIdx = 0;
-
long eldestTime = 0;
-
final int N = mNotificationList.size();
-
for (int i=0; i
-
NotificationRecord r = mNotificationList.get(i);
-
if (r.pkg.equals(pkg) && r.userId == userId) {
-
if (count == 0) {
-
eldestTime = r.notification.when;
-
eldestIdx = i;
-
}
-
else {
-
if (r.notification.when < eldestTime) {
-
eldestTime = r.notification.when;
-
eldestIdx = i;
-
}
-
}
-
count++;
-
if (count >= MAX_PACKAGE_NOTIFICATIONS) {
-
Slog.e(TAG, "Package has already posted " + count
-
+ " notifications. Not showing more. package=" + pkg);
-
//return;
-
// [ALPS00447419] SystemUI OOM: remove eldest entry
-
r = mNotificationList.get(eldestIdx);
-
mNotificationList.remove(eldestIdx);
-
cancelNotificationLocked(r, true);
-
break;
-
}
-
}
-
}
-
}
-
}
-
// This conditional is a dirty hack to limit the logging done on
-
// behalf of the download manager without affecting other apps.
-
if (!pkg.equals("com.android.providers.downloads")
-
|| Log.isLoggable("DownloadManager", Log.VERBOSE)) {
-
EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag,
-
userId,
-
notification.toString());
-
}
-
if (pkg == null || notification == null) {
-
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
-
+ " id=" + id + " notification=" + notification);
-
}
-
if (notification.icon != 0) {
-
if (notification.contentView == null) {
-
throw new IllegalArgumentException("contentView required: pkg=" + pkg
-
+ " id=" + id + " notification=" + notification);
-
}
-
}
-
// === Scoring ===
-
// 0. Sanitize inputs
-
notification.priority = clamp(notification.priority,
-
Notification.PRIORITY_MIN, Notification.PRIORITY_MAX);
-
// Migrate notification flags to scores
-
if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
-
if (notification.priority < Notification.PRIORITY_MAX)
-
notification.priority = Notification.PRIORITY_MAX;
-
} else if (SCORE_ONGOING_HIGHER && 0 != (notification.flags &
-
Notification.FLAG_ONGOING_EVENT)) {
-
if (notification.priority < Notification.PRIORITY_HIGH)
-
notification.priority = Notification.PRIORITY_HIGH;
-
}
-
// 1. initial score: buckets of 10, around the app
-
int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;
-
//[-20..20]
-
// 2. Consult external heuristics (TBD)
-
// 3. Apply local rules
-
// blocked apps
-
if (ENABLE_BLOCKED_NOTIFICATIONS && !isSystemNotification
-
&& !areNotificationsEnabledForPackageInt(pkg)) {
-
score = JUNK_SCORE;
-
Slog.e(TAG, "Suppressing notification from package " + pkg + " by user
-
request.");
-
}
-
if (DBG) {
-
Slog.v(TAG, "Assigned score=" + score + " to " + notification);
-
}
-
if (score < SCORE_DISPLAY_THRESHOLD) {
-
// Notification will be blocked because the score is too low.
-
return;
-
}
-
// Should this notification make noise, vibe, or use the LED?
-
final boolean canInterrupt = (score >=
-
SCORE_INTERRUPTION_THRESHOLD);
-
synchronized (mNotificationList) {
-
NotificationRecord r = new NotificationRecord(pkg, tag, id,
-
callingUid, callingPid, userId,
-
score,
-
notification);
-
NotificationRecord old = null;
-
int index = indexOfNotificationLocked(pkg, tag, id, userId);
-
if (index < 0) {
-
mNotificationList.add(r);
-
} else {
-
old = mNotificationList.remove(index);
-
mNotificationList.add(index, r);
-
// Make sure we don't lose the foreground service state.
-
if (old != null) {
-
notification.flags |=
-
old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
-
}
-
}
-
// Ensure if this is a foreground service that the proper additional
-
// flags are set.
-
if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0)
-
{
-
notification.flags |= Notification.FLAG_ONGOING_EVENT
-
| Notification.FLAG_NO_CLEAR;
-
}
-
final int currentUser;
-
final long token = Binder.clearCallingIdentity();
-
try {
-
currentUser = ActivityManager.getCurrentUser();
-
} finally {
-
Binder.restoreCallingIdentity(token);
-
}
-
if (notification.icon != 0) {
-
final StatusBarNotification n = new StatusBarNotification(
-
pkg, id, tag, r.uid, r.initialPid, score, notification, user);
-
if (old != null && old.statusBarKey != null) {
-
r.statusBarKey = old.statusBarKey;
-
long identity = Binder.clearCallingIdentity();
-
try {
-
mStatusBar.updateNotification(r.statusBarKey, n);
-
}
-
finally {
-
Binder.restoreCallingIdentity(identity);
-
}
-
} else {
-
long identity = Binder.clearCallingIdentity();
-
try {
-
r.statusBarKey = mStatusBar.addNotification(n);
-
if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
-
&& canInterrupt) {
-
mAttentionLight.pulse();
-
}
-
}
-
finally {
-
Binder.restoreCallingIdentity(identity);
-
}
-
}
-
// Send accessibility events only for the current user.
-
if (currentUser == userId) {
-
sendAccessibilityEvent(notification, pkg);
-
}
-
} else {
-
Slog.e(TAG, "Ignoring notification with icon==0: " + notification);
-
if (old != null && old.statusBarKey != null) {
-
long identity = Binder.clearCallingIdentity();
-
try {
-
mStatusBar.removeNotification(old.statusBarKey);
-
}
-
finally {
-
Binder.restoreCallingIdentity(identity);
-
}
-
}
-
}
-
// If we're not supposed to beep, vibrate, etc. then don't.
-
// ensure mms can send notification when a phone is calling
-
if ((((mDisabledNotifications &
-
StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) ||
-
pkg.equals("com.android.mms"))
-
&& (!(old != null
-
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) !=
-
0 ))
-
&& (r.userId == UserHandle.USER_ALL ||
-
(r.userId == userId && r.userId == currentUser))
-
&& canInterrupt
-
&& mSystemReady) {
-
///M:
-
if (DBG) {
-
Log.d(TAG,"pakage="+pkg+",In NotificationMangerService, this notification
-
soud, leds and vibrate enable");
-
}
-
final AudioManager audioManager = (AudioManager) mContext
-
.getSystemService(Context.AUDIO_SERVICE);
-
// sound
-
final boolean useDefaultSound =
-
(notification.defaults & Notification.DEFAULT_SOUND) != 0;
-
///M: log sound information
-
if (DBG) {
-
Log.d(TAG,"useDefaultSound="+useDefaultSound);
-
Log.d(TAG,"notification.sound="+notification.sound);
-
}
-
Uri soundUri = null;
-
boolean hasValidSound = false;
-
if (useDefaultSound) {
-
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
-
// check to see if the default notification sound is silent
-
ContentResolver resolver = mContext.getContentResolver();
-
hasValidSound = Settings.System.getString(resolver,
-
Settings.System.NOTIFICATION_SOUND) != null;
-
} else if (notification.sound != null) {
-
soundUri = notification.sound;
-
hasValidSound = (soundUri != null);
-
}
-
if (hasValidSound) {
-
boolean looping = (notification.flags & Notification.FLAG_INSISTENT) !=
-
0;
-
int audioStreamType;
-
if (notification.audioStreamType >= 0) {
-
audioStreamType = notification.audioStreamType;
-
} else {
-
audioStreamType = DEFAULT_STREAM_TYPE;
-
}
-
mSoundNotification = r;
-
///M: log sound information
-
if (DBG) {
-
Log.d(TAG,"looping="+looping);
-
Log.d(TAG,"audioStreamType="+audioStreamType);
-
Log.d(TAG,"StreamVolume="+audioManager.getStreamVolume(audioStreamType));
-
}
-
// do not play notifications if stream volume is 0
-
// (typically because ringer mode is silent) or if speech recognition is
-
active.
-
if ((audioManager.getStreamVolume(audioStreamType) != 0)
-
&& !audioManager.isSpeechRecognitionActive()) {
-
final long identity = Binder.clearCallingIdentity();
-
try {
-
final IRingtonePlayer player = mAudioService.getRingtonePlayer();
-
if (player != null) {
-
///M: [ALPS00461691]No notification sound when it detects wifi networks
-
if (user.getIdentifier() == UserHandle.USER_ALL) {
-
user = UserHandle.OWNER;
-
}
-
player.playAsync(soundUri, user, looping, audioStreamType);
-
}
-
} catch (RemoteException e) {
-
} finally {
-
Binder.restoreCallingIdentity(identity);
-
}
-
}
-
}
-
// vibrate
-
///M: for device manager
-
if (DBG) {
-
Log.d(TAG,"mDmLock="+mDmLock);
-
}
-
if (mDmLock == false){
-
// Does the notification want to specify its own vibration?
-
final boolean hasCustomVibrate = notification.vibrate != null;
-
// new in 4.2: if there was supposed to be a sound and we're in vibrate
-
mode,
-
// and no other vibration is specified, we fall back to vibration
-
final boolean convertSoundToVibration =
-
!hasCustomVibrate
-
&& hasValidSound
-
&& (audioManager.getRingerMode() ==
-
AudioManager.RINGER_MODE_VIBRATE);
-
// The DEFAULT_VIBRATE flag trumps any custom vibration AND the
-
fallback.
-
final boolean useDefaultVibrate =
-
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
-
if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
-
&& !(audioManager.getRingerMode() ==
-
AudioManager.RINGER_MODE_SILENT)) {
-
mVibrateNotification = r;
-
if (DBG) {
-
Log.w(TAG, "set vibrate!");
-
}
-
if (useDefaultVibrate || convertSoundToVibration) {
-
// Escalate privileges so we can use the vibrator even if the notifying
-
app
-
// does not have the VIBRATE permission.
-
long identity = Binder.clearCallingIdentity();
-
try {
-
mVibrator.vibrate(useDefaultVibrate ? mDefaultVibrationPattern
-
: mFallbackVibrationPattern,
-
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
-
} finally {
-
Binder.restoreCallingIdentity(identity);
-
}
-
} else if (notification.vibrate.length > 1) {
-
// If you want your own vibration pattern, you need the VIBRATE
-
permission
-
mVibrator.vibrate(notification.vibrate,
-
((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
-
}
-
}
-
} // mDmLock == false
-
}
-
// this option doesn't shut off the lights
-
// light
-
// the most recent thing gets the light
-
mLights.remove(old);
-
if (mLedNotification == old) {
-
mLedNotification = null;
-
}
-
//Slog.i(TAG, "notification.lights="
-
// + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS)
-
!= 0));
-
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
-
&& canInterrupt) {
-
mLights.add(r);
-
updateLightsLocked();
-
} else {
-
if (old != null
-
&& ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) !=
-
0)) {
-
updateLightsLocked();
-
}
-
}
-
}
-
idOut[0] = id;
- }
上面这个方法做的操作有点多,代码有300多行。其中有设计播放声音的地方:
java代码
-
"font-size:18px;"> player.playAsync(soundUri, user,
- looping, audioStreamType);
java代码
-
mVibrator.vibrate(notification.vibrate,
-
- ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
java代码
-
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS)
-
!= 0
-
-
&& canInterrupt) {
-
mLights.add(r);
-
updateLightsLocked();
- }
Step
3:updateLightsLocked()这个方法的代码如下:
java代码
-
// lock on mNotificationList
-
-
private void updateLightsLocked()
-
{
-
// handle notification lights
-
if (mLedNotification == null) {
-
// get next notification, if any
-
int n = mLights.size();
-
if (n > 0) {
-
mLedNotification = mLights.get(n-1);
-
}
-
}
-
// Don't flash while we are in a call or screen is on
-
///M: we need flash when screen is on
-
//mScreenOn add by lvmingfei for don't flash while screen is on in
-
2013-09-20
-
if (mLedNotification == null || mInCall || mCallRinging)) {
-
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;
-
}
-
if (mNotificationPulseEnabled) {
-
// pulse repeatedly
-
///M: log lights information
-
Log.d(TAG, "notification setFlashing ledOnMS = "+ledOnMS + " ledOffMS = "+
-
ledOffMS + ", ledARGB :" + ledARGB);
-
mNotificationLight.setFlashing(ledARGB,
-
LightsService.LIGHT_FLASH_TIMED,
-
ledOnMS, ledOffMS);
-
///M:
-
} else {
-
// pulse only once
-
mNotificationLight.pulse(ledARGB, ledOnMS);
-
}
-
}
- }
电话的状态是否是offhook,或来电的状态,会操作:java代码
- "font-size:18px;">mNotificationLight.turnOff();
-
"font-size:18px;">if
-
((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) !=0)
- {
-
"font-size:18px;">notification.defaults |=
- Notification.DEFAULT_LIGHTS;
- "font-size:18px;">mLedNotification.notification.ledARGB;
java代码
-
"font-size:18px;">mDefaultNotificationColor =
-
resources.getColor(
-
- com.android.internal.R.color.config_defaultNotificationColor);
java代码
-
"font-size:18px;">#ff0000ff
-
-
这个表示是蓝灯;具体想改成其他值;
-
#ff0000ff 表示蓝灯
-
#ff00ff00 表示绿灯
- #ffff0000 表示红灯
拓展:
如果想实现屏幕亮的时候,指示灯灭,屏幕灭的时候指示灯亮;可以监听ACTION_SCREEN_ON/ACTION_SCREEN_OFF的广播,搞一个全局的变量控制下;再调用updateNotificationPulse()这个方法,把变量的判断加载updateNotificationPulse()这个方法的灯亮灭判断的地方即可;
其次,我们来看看返回键的灯,即按键灯;
Step 1 :先来看看PowerManagerService.java这个类。按键灯的定义
java代码
-
"font-size:18px;"> private LightsService.Light
- mButtonLight;
-
"font-size:18px;">mButtonLight =
- mLightsService.getLight(LightsService.LIGHT_ID_BUTTONS);
-
"font-size:18px;"> if ( (newScreenState ==
-
DisplayPowerRequest.SCREEN_STATE_BRIGHT) && (mWakefulness ==
-
WAKEFULNESS_AWAKE) && !mIPOShutdown && !mShutdownFlag) {
-
-
if ( ( (mWakeLockSummary & WAKE_LOCK_BUTTON_BRIGHT) != 0 ) ||
-
( (mUserActivitySummary & USER_ACTIVITY_BUTTON_BRIGHT) != 0) ) {
-
mButtonLight.setBrightness(mScreenBrightness);
-
Slog.i(TAG, "setBrightness mButtonLight, mScreenBrightness=" +
-
mScreenBrightness);
-
} else {
-
mButtonLight.turnOff();
-
Slog.i(TAG, "setBrightness mButtonLight 0 ===.");
-
}
-
} else {
-
mButtonLight.turnOff();
-
Slog.i(TAG, "setBrightness mButtonLight else 0.");
- }
灯关闭的方法turnOff()
要想修改按键灯随p-sensor的灯的亮灭同步,可以参考Android4.2中Phone的P-sensor的应用的分析。
然后再加上上述控制灯亮灭的方法就可实现同步;
总结:灯的亮灭最后都会调用到LightsService.java这个类的,最后通过c代码调用底层的接口实现灯的颜色和闪烁的变化的;