伪原创,网络整理,作为自己学习的记录:
原文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代码调用底层的接口实现灯的颜色和闪烁的变化的;