Android中有各种灯,背光灯,按键灯,指示灯,等等;前几天修改了这部分代码,整理下思路,其实都不难;

首先,来说说指示灯(提示灯),即未接电话,未接短信的时候,会闪灯,这个其实就是NotificationManager这个类中的notify()方法来处理的;流程简单来过一下:

Step 1:从应用层发送的notify(),到framework层被NotificationManager.java这个类接受了,来看看这个notify()这个方法:

[java] view plain copy  print?
  1. public void notify(int id, Notification notification)
  2. {
  3. notify(null, id, notification);
  4. }
[java] view plain copy  print?
  1. public void notify(String tag, int id, Notification notification)
  2. {
  3. int[] idOut = new int[1];
  4. INotificationManager service = getService();
  5. String pkg = mContext.getPackageName();
  6. if (notification.sound != null) {
  7. notification.sound = notification.sound.getCanonicalUri();
  8. }
  9. if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
  10. try {
  11. service.enqueueNotificationWithTag(pkg, tag, id, notification, idOut,
  12. UserHandle.myUserId());
  13. if (id != idOut[0]) {
  14. Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
  15. }
  16. } catch (RemoteException e) {
  17. }
  18. }

重点关注这个enqueueNotificationWithTag()这个方法,这个方法首先会取是否传递过来了声音的Uri,如果传递了,就保存下来,给等会播放用;

Step 2:enqueueNotificationWithTag()这个方法调用到了NotificationManagerService.java这个类中去了,来看看这个方法:

[java] view plain copy  print?
  1. public void enqueueNotificationWithTag(String pkg, String tag, int id, Notification notification,
  2. int[] idOut, int userId)
  3. {
  4. enqueueNotificationInternal(pkg, Binder.getCallingUid(), Binder.getCallingPid(),
  5. tag, id, notification, idOut, userId);
  6. }
[java] view plain copy  print?
  1. // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
  2. // uid/pid of another application)
  3. public void enqueueNotificationInternal(String pkg, int callingUid, int callingPid,
  4. String tag, int id, Notification notification, int[] idOut, int userId)
  5. {
  6. if (DBG) {
  7. Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification + ", notification.ledARGB : "+ notification.ledARGB);
  8. }
  9. checkCallerIsSystemOrSameApp(pkg);
  10. final boolean isSystemNotification = ("android".equals(pkg));
  11. userId = ActivityManager.handleIncomingUser(callingPid,
  12. callingUid, userId, true, false, "enqueueNotification", pkg);
  13. UserHandle user = new UserHandle(userId);
  14. // Limit the number of notifications that any given package except the android
  15. // package can enqueue.  Prevents DOS attacks and deals with leaks.
  16. if (!isSystemNotification) {
  17. synchronized (mNotificationList) {
  18. int count = 0;
  19. int eldestIdx = 0;
  20. long eldestTime = 0;
  21. final int N = mNotificationList.size();
  22. for (int i=0; i<N; i++) {
  23. NotificationRecord r = mNotificationList.get(i);
  24. if (r.pkg.equals(pkg) && r.userId == userId) {
  25. if (count == 0) {
  26. eldestTime = r.notification.when;
  27. eldestIdx = i;
  28. }
  29. else {
  30. if (r.notification.when < eldestTime) {
  31. eldestTime = r.notification.when;
  32. eldestIdx = i;
  33. }
  34. }
  35. count++;
  36. if (count >= MAX_PACKAGE_NOTIFICATIONS) {
  37. Slog.e(TAG, "Package has already posted " + count
  38. + " notifications.  Not showing more.  package=" + pkg);
  39. //return;
  40. // [ALPS00447419] SystemUI OOM: remove eldest entry
  41. r = mNotificationList.get(eldestIdx);
  42. mNotificationList.remove(eldestIdx);
  43. cancelNotificationLocked(r, true);
  44. break;
  45. }
  46. }
  47. }
  48. }
  49. }
  50. // This conditional is a dirty hack to limit the logging done on
  51. //     behalf of the download manager without affecting other apps.
  52. if (!pkg.equals("com.android.providers.downloads")
  53. || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
  54. EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag, userId,
  55. notification.toString());
  56. }
  57. if (pkg == null || notification == null) {
  58. throw new IllegalArgumentException("null not allowed: pkg=" + pkg
  59. + " id=" + id + " notification=" + notification);
  60. }
  61. if (notification.icon != 0) {
  62. if (notification.contentView == null) {
  63. throw new IllegalArgumentException("contentView required: pkg=" + pkg
  64. + " id=" + id + " notification=" + notification);
  65. }
  66. }
  67. // === Scoring ===
  68. // 0. Sanitize inputs
  69. notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX);
  70. // Migrate notification flags to scores
  71. if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
  72. if (notification.priority < Notification.PRIORITY_MAX) notification.priority = Notification.PRIORITY_MAX;
  73. } else if (SCORE_ONGOING_HIGHER && 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
  74. if (notification.priority < Notification.PRIORITY_HIGH) notification.priority = Notification.PRIORITY_HIGH;
  75. }
  76. // 1. initial score: buckets of 10, around the app
  77. int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
  78. // 2. Consult external heuristics (TBD)
  79. // 3. Apply local rules
  80. // blocked apps
  81. if (ENABLE_BLOCKED_NOTIFICATIONS && !isSystemNotification && !areNotificationsEnabledForPackageInt(pkg)) {
  82. score = JUNK_SCORE;
  83. Slog.e(TAG, "Suppressing notification from package " + pkg + " by user request.");
  84. }
  85. if (DBG) {
  86. Slog.v(TAG, "Assigned score=" + score + " to " + notification);
  87. }
  88. if (score < SCORE_DISPLAY_THRESHOLD) {
  89. // Notification will be blocked because the score is too low.
  90. return;
  91. }
  92. // Should this notification make noise, vibe, or use the LED?
  93. final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD);
  94. synchronized (mNotificationList) {
  95. NotificationRecord r = new NotificationRecord(pkg, tag, id,
  96. callingUid, callingPid, userId,
  97. score,
  98. notification);
  99. NotificationRecord old = null;
  100. int index = indexOfNotificationLocked(pkg, tag, id, userId);
  101. if (index < 0) {
  102. mNotificationList.add(r);
  103. } else {
  104. old = mNotificationList.remove(index);
  105. mNotificationList.add(index, r);
  106. // Make sure we don't lose the foreground service state.
  107. if (old != null) {
  108. notification.flags |=
  109. old.notification.flags&Notification.FLAG_FOREGROUND_SERVICE;
  110. }
  111. }
  112. // Ensure if this is a foreground service that the proper additional
  113. // flags are set.
  114. if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
  115. notification.flags |= Notification.FLAG_ONGOING_EVENT
  116. | Notification.FLAG_NO_CLEAR;
  117. }
  118. final int currentUser;
  119. final long token = Binder.clearCallingIdentity();
  120. try {
  121. currentUser = ActivityManager.getCurrentUser();
  122. } finally {
  123. Binder.restoreCallingIdentity(token);
  124. }
  125. if (notification.icon != 0) {
  126. final StatusBarNotification n = new StatusBarNotification(
  127. pkg, id, tag, r.uid, r.initialPid, score, notification, user);
  128. if (old != null && old.statusBarKey != null) {
  129. r.statusBarKey = old.statusBarKey;
  130. long identity = Binder.clearCallingIdentity();
  131. try {
  132. mStatusBar.updateNotification(r.statusBarKey, n);
  133. }
  134. finally {
  135. Binder.restoreCallingIdentity(identity);
  136. }
  137. } else {
  138. long identity = Binder.clearCallingIdentity();
  139. try {
  140. r.statusBarKey = mStatusBar.addNotification(n);
  141. if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
  142. && canInterrupt) {
  143. mAttentionLight.pulse();
  144. }
  145. }
  146. finally {
  147. Binder.restoreCallingIdentity(identity);
  148. }
  149. }
  150. // Send accessibility events only for the current user.
  151. if (currentUser == userId) {
  152. sendAccessibilityEvent(notification, pkg);
  153. }
  154. } else {
  155. Slog.e(TAG, "Ignoring notification with icon==0: " + notification);
  156. if (old != null && old.statusBarKey != null) {
  157. long identity = Binder.clearCallingIdentity();
  158. try {
  159. mStatusBar.removeNotification(old.statusBarKey);
  160. }
  161. finally {
  162. Binder.restoreCallingIdentity(identity);
  163. }
  164. }
  165. }
  166. // If we're not supposed to beep, vibrate, etc. then don't.
  167. // ensure mms can send notification when a phone is calling
  168. if ((((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0) || pkg.equals("com.android.mms"))
  169. && (!(old != null
  170. && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
  171. && (r.userId == UserHandle.USER_ALL ||
  172. (r.userId == userId && r.userId == currentUser))
  173. && canInterrupt
  174. && mSystemReady) {
  175. ///M:
  176. if (DBG) {
  177. Log.d(TAG,"pakage="+pkg+",In NotificationMangerService, this notification soud, leds and vibrate enable");
  178. }
  179. final AudioManager audioManager = (AudioManager) mContext
  180. .getSystemService(Context.AUDIO_SERVICE);
  181. // sound
  182. final boolean useDefaultSound =
  183. (notification.defaults & Notification.DEFAULT_SOUND) != 0;
  184. ///M: log sound information
  185. if (DBG) {
  186. Log.d(TAG,"useDefaultSound="+useDefaultSound);
  187. Log.d(TAG,"notification.sound="+notification.sound);
  188. }
  189. Uri soundUri = null;
  190. boolean hasValidSound = false;
  191. if (useDefaultSound) {
  192. soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
  193. // check to see if the default notification sound is silent
  194. ContentResolver resolver = mContext.getContentResolver();
  195. hasValidSound = Settings.System.getString(resolver,
  196. Settings.System.NOTIFICATION_SOUND) != null;
  197. } else if (notification.sound != null) {
  198. soundUri = notification.sound;
  199. hasValidSound = (soundUri != null);
  200. }
  201. if (hasValidSound) {
  202. boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
  203. int audioStreamType;
  204. if (notification.audioStreamType >= 0) {
  205. audioStreamType = notification.audioStreamType;
  206. } else {
  207. audioStreamType = DEFAULT_STREAM_TYPE;
  208. }
  209. mSoundNotification = r;
  210. ///M: log sound information
  211. if (DBG) {
  212. Log.d(TAG,"looping="+looping);
  213. Log.d(TAG,"audioStreamType="+audioStreamType);
  214. Log.d(TAG,"StreamVolume="+audioManager.getStreamVolume(audioStreamType));
  215. }
  216. // do not play notifications if stream volume is 0
  217. // (typically because ringer mode is silent) or if speech recognition is active.
  218. if ((audioManager.getStreamVolume(audioStreamType) != 0)
  219. && !audioManager.isSpeechRecognitionActive()) {
  220. final long identity = Binder.clearCallingIdentity();
  221. try {
  222. final IRingtonePlayer player = mAudioService.getRingtonePlayer();
  223. if (player != null) {
  224. ///M: [ALPS00461691]No notification sound when it detects wifi networks
  225. if (user.getIdentifier() == UserHandle.USER_ALL) {
  226. user = UserHandle.OWNER;
  227. }
  228. player.playAsync(soundUri, user, looping, audioStreamType);
  229. }
  230. } catch (RemoteException e) {
  231. } finally {
  232. Binder.restoreCallingIdentity(identity);
  233. }
  234. }
  235. }
  236. // vibrate
  237. ///M: for device manager
  238. if (DBG) {
  239. Log.d(TAG,"mDmLock="+mDmLock);
  240. }
  241. if (mDmLock == false){
  242. // Does the notification want to specify its own vibration?
  243. final boolean hasCustomVibrate = notification.vibrate != null;
  244. // new in 4.2: if there was supposed to be a sound and we're in vibrate mode,
  245. // and no other vibration is specified, we fall back to vibration
  246. final boolean convertSoundToVibration =
  247. !hasCustomVibrate
  248. && hasValidSound
  249. && (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
  250. // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
  251. final boolean useDefaultVibrate =
  252. (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
  253. if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
  254. && !(audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) {
  255. mVibrateNotification = r;
  256. if (DBG) {
  257. Log.w(TAG, "set vibrate!");
  258. }
  259. if (useDefaultVibrate || convertSoundToVibration) {
  260. // Escalate privileges so we can use the vibrator even if the notifying app
  261. // does not have the VIBRATE permission.
  262. long identity = Binder.clearCallingIdentity();
  263. try {
  264. mVibrator.vibrate(useDefaultVibrate ? mDefaultVibrationPattern
  265. : mFallbackVibrationPattern,
  266. ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
  267. } finally {
  268. Binder.restoreCallingIdentity(identity);
  269. }
  270. } else if (notification.vibrate.length > 1) {
  271. // If you want your own vibration pattern, you need the VIBRATE permission
  272. mVibrator.vibrate(notification.vibrate,
  273. ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
  274. }
  275. }
  276. } // mDmLock == false
  277. }
  278. // this option doesn't shut off the lights
  279. // light
  280. // the most recent thing gets the light
  281. mLights.remove(old);
  282. if (mLedNotification == old) {
  283. mLedNotification = null;
  284. }
  285. //Slog.i(TAG, "notification.lights="
  286. //        + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS) != 0));
  287. if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
  288. && canInterrupt) {
  289. mLights.add(r);
  290. updateLightsLocked();
  291. } else {
  292. if (old != null
  293. && ((old.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0)) {
  294. updateLightsLocked();
  295. }
  296. }
  297. }
  298. idOut[0] = id;
  299. }

上面这个方法做的操作有点多,代码有300多行。其中有设计播放声音的地方:

[java] view plain copy  print?
  1. <span style="font-size:18px;"> player.playAsync(soundUri, user, looping, audioStreamType);</span>

有是否播放震动的地方:

[java] view plain copy  print?
  1. mVibrator.vibrate(notification.vibrate,
  2. ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);

最后闪灯的地方在这个逻辑中:

[java] view plain copy  print?
  1. if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
  2. && canInterrupt) {
  3. mLights.add(r);
  4. updateLightsLocked();
  5. }

重点看updateLightsLocked()这个方法,这个方法里面有逻辑的操作;

  Step 3:updateLightsLocked()这个方法的代码如下:

[java] view plain copy  print?
  1. // lock on mNotificationList
  2. private void updateLightsLocked()
  3. {
  4. // handle notification lights
  5. if (mLedNotification == null) {
  6. // get next notification, if any
  7. int n = mLights.size();
  8. if (n > 0) {
  9. mLedNotification = mLights.get(n-1);
  10. }
  11. }
  12. // Don't flash while we are in a call or screen is on
  13. ///M: we need flash when screen is on
  14. //mScreenOn add by lvmingfei for don't flash while screen is on in 2013-09-20
  15. if (mLedNotification == null || mInCall || mCallRinging)) {
  16. mNotificationLight.turnOff();
  17. } else {
  18. int ledARGB = mLedNotification.notification.ledARGB;
  19. int ledOnMS = mLedNotification.notification.ledOnMS;
  20. int ledOffMS = mLedNotification.notification.ledOffMS;
  21. if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {
  22. ledARGB = mDefaultNotificationColor;
  23. ledOnMS = mDefaultNotificationLedOn;
  24. ledOffMS = mDefaultNotificationLedOff;
  25. }
  26. if (mNotificationPulseEnabled) {
  27. // pulse repeatedly
  28. ///M: log lights information
  29. Log.d(TAG, "notification setFlashing ledOnMS = "+ledOnMS + " ledOffMS = "+ ledOffMS + ", ledARGB :" + ledARGB);
  30. mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
  31. ledOnMS, ledOffMS);
  32. ///M:
  33. } else {
  34. // pulse only once
  35. mNotificationLight.pulse(ledARGB, ledOnMS);
  36. }
  37. }
  38. }

这段代码中有如下操作,判断一些变量的状态,以决定时候关闭指示灯,还是闪光,还是只闪一次的操作;
电话的状态是否是offhook,或来电的状态,会操作:

[java] view plain copy  print?
  1. <span style="font-size:18px;">mNotificationLight.turnOff();</span>

下面这个条件也很重要:

[java] view plain copy  print?
  1. <span style="font-size:18px;">if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {</span>

未解来电,或短信的时候这个值会设置为

[java] view plain copy  print?
  1. <span style="font-size:18px;">notification.defaults |= Notification.DEFAULT_LIGHTS;</span>

这个值是4,那么上面的这个判断就为true了,所以灯的颜色就不是由

[java] view plain copy  print?
  1. <span style="font-size:18px;">mLedNotification.notification.ledARGB;</span>

这个值决定的了,而是由mDefaultNotificationColor这个值决定的,这个值的定义在

[java] view plain copy  print?
  1. <span style="font-size:18px;">mDefaultNotificationColor = resources.getColor(
  2. com.android.internal.R.color.config_defaultNotificationColor);</span>

这个值的定义在framework/base/core/res/res/values/config.xml中定义的,

[java] view plain copy  print?
  1. <span style="font-size:18px;"><color name="config_defaultNotificationColor">#ff0000ff</color></span>

这个表示是蓝灯;具体想改成其他值;

  1. #ff0000ff 表示蓝灯
  2. #ff00ff00 表示绿灯
  3. #ffff0000 表示红灯

后面的逻辑就调用到LightsService.java中去了,这个类是管理灯的类,(背光灯,按键灯,指示灯等等);

拓展:

如果想实现屏幕亮的时候,指示灯灭,屏幕灭的时候指示灯亮;可以监听ACTION_SCREEN_ON/ACTION_SCREEN_OFF的广播,搞一个全局的变量控制下;再调用updateNotificationPulse()这个方法,把变量的判断加载updateNotificationPulse()这个方法的灯亮灭判断的地方即可;

其次,我们来看看返回键的灯,即按键灯;

Step 1 :先来看看PowerManagerService.java这个类。按键灯的定义

[java] view plain copy  print?
  1. <span style="font-size:18px;"> private LightsService.Light mButtonLight;</span>

初始化方法:

[java] view plain copy  print?
  1. <span style="font-size:18px;">mButtonLight = mLightsService.getLight(LightsService.LIGHT_ID_BUTTONS);</span>
[java] view plain copy  print?
  1. <span style="font-size:18px;"> if ( (newScreenState == DisplayPowerRequest.SCREEN_STATE_BRIGHT) && (mWakefulness == WAKEFULNESS_AWAKE) && !mIPOShutdown && !mShutdownFlag) {
  2. if ( ( (mWakeLockSummary & WAKE_LOCK_BUTTON_BRIGHT) != 0 ) ||
  3. ( (mUserActivitySummary & USER_ACTIVITY_BUTTON_BRIGHT) != 0) ) {
  4. mButtonLight.setBrightness(mScreenBrightness);
  5. Slog.i(TAG, "setBrightness mButtonLight, mScreenBrightness=" + mScreenBrightness);
  6. } else {
  7. mButtonLight.turnOff();
  8. Slog.i(TAG, "setBrightness mButtonLight 0 ===.");
  9. }
  10. } else {
  11. mButtonLight.turnOff();
  12. Slog.i(TAG, "setBrightness mButtonLight else 0.");
  13. }</span>

灯的点亮的方法setBrightness()

灯关闭的方法turnOff()

要想修改按键灯随p-sensor的灯的亮灭同步,可以参考Android4.2中Phone的P-sensor的应用的分析。

然后再加上上述控制灯亮灭的方法就可实现同步;

总结:灯的亮灭最后都会调用到LightsService.java这个类的,最后通过c代码调用底层的接口实现灯的颜色和闪烁的变化的;

最终通过JNI调用vendor\mediatek\proprietary\hardware\liblights\lights.c

另外三色灯底层是写死的只能三色,要是自定义请修改lights.c

/* Copyright Statement:** This software/firmware and related documentation ("MediaTek Software") are* protected under relevant copyright laws. The information contained herein is* confidential and proprietary to MediaTek Inc. and/or its licensors. Without* the prior written permission of MediaTek inc. and/or its licensors, any* reproduction, modification, use or disclosure of MediaTek Software, and* information contained herein, in whole or in part, shall be strictly* prohibited.* * MediaTek Inc. (C) 2010. All rights reserved.* * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER* ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL* WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR* NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH* RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,* INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES* TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.* RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO* OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK* SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE* RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S* ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE* RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE* MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE* CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.** The following software/firmware and/or related documentation ("MediaTek* Software") have been modified by MediaTek Inc. All revisions are subject to* any receiver's applicable license agreements with MediaTek Inc.*//** Copyright (C) 2008 The Android Open Source 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.*/#define LOG_TAG "lights"#include <cutils/log.h>#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <time.h>#include <sys/ioctl.h>
#include <sys/types.h>#include <hardware/lights.h>#define LIGHTS_DBG_ON
/******************************************************************************/static pthread_once_t g_init = PTHREAD_ONCE_INIT;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
static int g_haveTrackballLight = 0;
static struct light_state_t g_notification;
static struct light_state_t g_battery;
static int g_backlight = 255;
static int g_trackball = -1;
static int g_buttons = 0;
static int g_attention = 0;/* TRACKBALL BACKLIGHT */
char const*const TRACKBALL_FILE= "/sys/class/leds/jogball-backlight/brightness";/* RED LED */
char const*const RED_LED_FILE= "/sys/class/leds/red/brightness";char const*const RED_TRIGGER_FILE= "/sys/class/leds/red/trigger";char const*const RED_DELAY_ON_FILE= "/sys/class/leds/red/delay_on";char const*const RED_DELAY_OFF_FILE= "/sys/class/leds/red/delay_off";/* GREEN LED */
char const*const GREEN_LED_FILE= "/sys/class/leds/green/brightness";char const*const GREEN_TRIGGER_FILE= "/sys/class/leds/green/trigger";char const*const GREEN_DELAY_ON_FILE= "/sys/class/leds/green/delay_on";char const*const GREEN_DELAY_OFF_FILE= "/sys/class/leds/green/delay_off";/* BLUE LED */
char const*const BLUE_LED_FILE= "/sys/class/leds/blue/brightness";char const*const BLUE_TRIGGER_FILE= "/sys/class/leds/blue/trigger";char const*const BLUE_DELAY_ON_FILE= "/sys/class/leds/blue/delay_on";char const*const BLUE_DELAY_OFF_FILE= "/sys/class/leds/blue/delay_off";/* LCD BACKLIGHT */
char const*const LCD_FILE= "/sys/class/leds/lcd-backlight/brightness";/* KEYBOARD BACKLIGHT */
char const*const KEYBOARD_FILE= "/sys/class/leds/keyboard-backlight/brightness";/* BUTTON BACKLIGHT */
char const*const BUTTON_FILE= "/sys/class/leds/button-backlight/brightness";//ALPS0804285 add for delay
int led_wait_delay(int ms)
{struct timespec req = {.tv_sec = 0, .tv_nsec = ms*1000000};struct timespec rem;int ret = nanosleep(&req, &rem);while(ret){if(errno == EINTR){req.tv_sec  = rem.tv_sec;req.tv_nsec = rem.tv_nsec;ret = nanosleep(&req, &rem);}else{perror("nanosleep");return errno;}}return 0;
}/*** device methods*/void init_globals(void)
{// init the mutexpthread_mutex_init(&g_lock, NULL);// figure out if we have the trackball LED or notg_haveTrackballLight = (access(TRACKBALL_FILE, W_OK) == 0) ? 1 : 0;}static int
write_int(char const* path, int value)
{int fd;#ifdef LIGHTS_INFO_ONALOGD("write %d to %s", value, path);
#endiffd = open(path, O_RDWR);ALOGD("write_int open fd=%d\n", fd);if (fd >= 0) {char buffer[20];int bytes = sprintf(buffer, "%d\n", value);int amt = write(fd, buffer, bytes);close(fd);return amt == -1 ? -errno : 0;} else {return -errno;}
}static int
write_str(char const* path, char *str)
{int fd;#ifdef LIGHTS_INFO_ONALOGD("write %s to %s", str, path);
#endiffd = open(path, O_WRONLY);if (fd >= 0) {char buffer[20];int bytes = sprintf(buffer, "%s", str);int amt = write(fd, buffer, bytes);close(fd);return amt == -1 ? -errno : 0;} else {return -errno;}
}static int
is_lit(struct light_state_t const* state)
{return state->color & 0x00ffffff;
}static int
blink_red(int level, int onMS, int offMS)
{static int preStatus = 0; // 0: off, 1: blink, 2: no blinkint nowStatus;int i = 0;if (level == 0)nowStatus = 0;else if (onMS && offMS)nowStatus = 1;elsenowStatus = 2;if (preStatus == nowStatus)return -1;#ifdef LIGHTS_DBG_ONALOGD("blink_red, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
#endifif (nowStatus == 0) {write_int(RED_LED_FILE, 0);}else if (nowStatus == 1) {
//          write_int(RED_LED_FILE, level); // default full brightnesswrite_str(RED_TRIGGER_FILE, "timer");while (((access(RED_DELAY_OFF_FILE, F_OK) == -1) || (access(RED_DELAY_OFF_FILE, R_OK|W_OK) == -1)) && i<10) {ALOGD("RED_DELAY_OFF_FILE doesn't exist or cannot write!!\n");led_wait_delay(5);//sleep 5ms for wait kernel LED class create led delay_off/delay_on node of fsi++;}write_int(RED_DELAY_OFF_FILE, offMS);write_int(RED_DELAY_ON_FILE, onMS);}else {write_str(RED_TRIGGER_FILE, "none");write_int(RED_LED_FILE, 255); // default full brightness}preStatus = nowStatus;return 0;
}static int
blink_green(int level, int onMS, int offMS)
{static int preStatus = 0; // 0: off, 1: blink, 2: no blinkint nowStatus;int i = 0;if (level == 0)nowStatus = 0;else if (onMS && offMS)nowStatus = 1;elsenowStatus = 2;if (preStatus == nowStatus)return -1;#ifdef LIGHTS_DBG_ONALOGD("blink_green, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
#endifif (nowStatus == 0) {write_int(GREEN_LED_FILE, 0);}else if (nowStatus == 1) {
//          write_int(GREEN_LED_FILE, level); // default full brightnesswrite_str(GREEN_TRIGGER_FILE, "timer");while (((access(GREEN_DELAY_OFF_FILE, F_OK) == -1) || (access(GREEN_DELAY_OFF_FILE, R_OK|W_OK) == -1)) && i<10) {ALOGD("GREEN_DELAY_OFF_FILE doesn't exist or cannot write!!\n");led_wait_delay(5);//sleep 5ms for wait kernel LED class create led delay_off/delay_on node of fsi++;}write_int(GREEN_DELAY_OFF_FILE, offMS);write_int(GREEN_DELAY_ON_FILE, onMS);}else {write_str(GREEN_TRIGGER_FILE, "none");write_int(GREEN_LED_FILE, 255); // default full brightness}preStatus = nowStatus;return 0;
}static int
blink_blue(int level, int onMS, int offMS)
{static int preStatus = 0; // 0: off, 1: blink, 2: no blinkint nowStatus;int i = 0;if (level == 0)nowStatus = 0;else if (onMS && offMS)nowStatus = 1;elsenowStatus = 2;if (preStatus == nowStatus)return -1;#ifdef LIGHTS_DBG_ONALOGD("blink_blue, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
#endifif (nowStatus == 0) {write_int(BLUE_LED_FILE, 0);}else if (nowStatus == 1) {
//          write_int(BLUE_LED_FILE, level); // default full brightnesswrite_str(BLUE_TRIGGER_FILE, "timer");while (((access(BLUE_DELAY_OFF_FILE, F_OK) == -1) || (access(BLUE_DELAY_OFF_FILE, R_OK|W_OK) == -1)) && i<10) {ALOGD("BLUE_DELAY_OFF_FILE doesn't exist or cannot write!!\n");led_wait_delay(5);//sleep 5ms for wait kernel LED class create led delay_off/delay_on node of fsi++;}write_int(BLUE_DELAY_OFF_FILE, offMS);write_int(BLUE_DELAY_ON_FILE, onMS);}else {write_str(BLUE_TRIGGER_FILE, "none");write_int(BLUE_LED_FILE, 255); // default full brightness}preStatus = nowStatus;return 0;
}static int
handle_trackball_light_locked(struct light_device_t* dev)
{int mode = g_attention;if (mode == 7 && g_backlight) {mode = 0;}ALOGV("%s g_backlight = %d, mode = %d, g_attention = %d\n",__func__, g_backlight, mode, g_attention);// If the value isn't changing, don't set it, because this// can reset the timer on the breathing mode, which looks bad.if (g_trackball == mode) {return 0;}return write_int(TRACKBALL_FILE, mode);
}static int
rgb_to_brightness(struct light_state_t const* state)
{int color = state->color & 0x00ffffff;return ((77*((color>>16)&0x00ff))+ (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
}static int
set_light_backlight(struct light_device_t* dev,struct light_state_t const* state)
{int err = 0;int brightness = rgb_to_brightness(state);pthread_mutex_lock(&g_lock);g_backlight = brightness;err = write_int(LCD_FILE, brightness);if (g_haveTrackballLight) {handle_trackball_light_locked(dev);}pthread_mutex_unlock(&g_lock);return err;
}static int
set_light_keyboard(struct light_device_t* dev,struct light_state_t const* state)
{int err = 0;int on = is_lit(state);pthread_mutex_lock(&g_lock);err = write_int(KEYBOARD_FILE, on?255:0);pthread_mutex_unlock(&g_lock);return err;
}static int
set_light_buttons(struct light_device_t* dev,struct light_state_t const* state)
{int err = 0;int on = is_lit(state);pthread_mutex_lock(&g_lock);g_buttons = on;err = write_int(BUTTON_FILE, on?255:0);pthread_mutex_unlock(&g_lock);return err;
}static int
set_speaker_light_locked(struct light_device_t* dev,struct light_state_t const* state)
{int len;int alpha, red, green, blue;int onMS, offMS;unsigned int colorRGB;switch (state->flashMode) {case LIGHT_FLASH_TIMED:onMS = state->flashOnMS;offMS = state->flashOffMS;break;case LIGHT_FLASH_NONE:default:onMS = 0;offMS = 0;break;}colorRGB = state->color;#ifdef LIGHTS_DBG_ONALOGD("set_led_state colorRGB=%08X, onMS=%d, offMS=%d\n",colorRGB, onMS, offMS);
#endifalpha = (colorRGB >> 24) & 0xFF;if (alpha) {red = (colorRGB >> 16) & 0xFF;green = (colorRGB >> 8) & 0xFF;blue = colorRGB & 0xFF;} else { // alpha = 0 means turn the LED offred = green = blue = 0;}if (red) {blink_green(0, 0, 0);blink_blue(0, 0, 0);blink_red(red, onMS, offMS);}else if (green) {blink_red(0, 0, 0);blink_blue(0, 0, 0);blink_green(green, onMS, offMS);}else if (blue) {blink_red(0, 0, 0);blink_green(0, 0, 0);blink_blue(blue, onMS, offMS);}else {blink_red(0, 0, 0);blink_green(0, 0, 0);blink_blue(0, 0, 0);}return 0;
}static void
handle_speaker_battery_locked(struct light_device_t* dev)
{if (is_lit(&g_battery)) {set_speaker_light_locked(dev, &g_battery);} else {set_speaker_light_locked(dev, &g_battery); /*Turkey workaround: notification and Low battery case, IPO bootup, NLED cannot blink*/set_speaker_light_locked(dev, &g_notification);}
}static int
set_light_battery(struct light_device_t* dev,struct light_state_t const* state)
{pthread_mutex_lock(&g_lock);g_battery = *state;if (g_haveTrackballLight) {set_speaker_light_locked(dev, state);}handle_speaker_battery_locked(dev);pthread_mutex_unlock(&g_lock);return 0;
}static int
set_light_notifications(struct light_device_t* dev,struct light_state_t const* state)
{pthread_mutex_lock(&g_lock);g_notification = *state;ALOGV("set_light_notifications g_trackball=%d color=0x%08x",g_trackball, state->color);if (g_haveTrackballLight) {handle_trackball_light_locked(dev);}handle_speaker_battery_locked(dev);pthread_mutex_unlock(&g_lock);return 0;
}static int
set_light_attention(struct light_device_t* dev,struct light_state_t const* state)
{pthread_mutex_lock(&g_lock);ALOGV("set_light_attention g_trackball=%d color=0x%08x",g_trackball, state->color);if (state->flashMode == LIGHT_FLASH_HARDWARE) {g_attention = state->flashOnMS;} else if (state->flashMode == LIGHT_FLASH_NONE) {g_attention = 0;}if (g_haveTrackballLight) {handle_trackball_light_locked(dev);}pthread_mutex_unlock(&g_lock);return 0;
}/** Close the lights device */
static int
close_lights(struct light_device_t *dev)
{if (dev) {free(dev);}return 0;
}/******************************************************************************//*** module methods*//** Open a new instance of a lights device using name */
static int open_lights(const struct hw_module_t* module, char const* name,struct hw_device_t** device)
{int (*set_light)(struct light_device_t* dev,struct light_state_t const* state);if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {set_light = set_light_backlight;}else if (0 == strcmp(LIGHT_ID_KEYBOARD, name)) {set_light = set_light_keyboard;}else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {set_light = set_light_buttons;}else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {set_light = set_light_battery;}else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {set_light = set_light_notifications;}else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) {set_light = set_light_attention;}else {return -EINVAL;}pthread_once(&g_init, init_globals);struct light_device_t *dev = malloc(sizeof(struct light_device_t));memset(dev, 0, sizeof(*dev));dev->common.tag = HARDWARE_DEVICE_TAG;dev->common.version = 0;dev->common.module = (struct hw_module_t*)module;dev->common.close = (int (*)(struct hw_device_t*))close_lights;dev->set_light = set_light;*device = (struct hw_device_t*)dev;return 0;
}static struct hw_module_methods_t lights_module_methods = {.open =  open_lights,
};/** The lights Module*/
struct hw_module_t HAL_MODULE_INFO_SYM = {.tag = HARDWARE_MODULE_TAG,//.version_major = 1,//.version_minor = 0,.id = LIGHTS_HARDWARE_MODULE_ID,.name = "MTK lights Module",.author = "MediaTek",.methods = &lights_module_methods,
};

Android Light开发(二) 通知灯调用过程相关推荐

  1. Android画板开发(二) 橡皮擦实现

    Android画板开发(一) 基本画笔的实现 Android画板开发(二) 橡皮擦实现 Android画板开发(三) 撤销反撤销功能实现 Android画板开发(四) 添加背景和保存画板内容为图片 A ...

  2. 【Android游戏开发二十七】讲解游戏开发与项目下的hdpi 、mdpi与ldpi资源文件夹以及游戏高清版本的设置...

    今天一个开发者问到我为什么游戏开发要删除项目下的hdpi.mdpi和ldpi文件夹:下面详细给大家解答一下: 首先童鞋们如果看过我写的<[Android游戏开发二十一]Android os设备谎 ...

  3. Android NDK开发: 通过C/C++调用第三方so库

    文章目录 一.编写so库代码 二.安装Android NDK 三.编译so库 3.1 编辑Android.mk 3.2 编辑Application.mk 3.3 编译 四.集成到Android工程中 ...

  4. Android 蓝牙开发(二) --手机与蓝牙音箱配对,并播放音频

    Android 蓝牙开发(一) – 传统蓝牙聊天室 Android 蓝牙开发(三) – 低功耗蓝牙开发 项目工程BluetoothDemo 上一章中,我们已经学习了传统蓝牙的开发,这一章,我们来学习如 ...

  5. 【Android游戏开发二十二】(图文详解)游戏中灵活实现动画播放!简述J2me的游戏类库与Android游戏开发!

    本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/andr ...

  6. 移动应用开发技术——Android Studio实验二——Activity的调用——竹园摘竹子

    掌握线性布局和相对布局的使用方法 掌握基本控件的属性功能及使用方法 掌握Activity的数据回传 通过线性布局和相对布局来搭建两个Activity界面,界面效果如下图所示.当点击"去竹园按 ...

  7. CSDN Android客户端开发(二):详解如何基于Java用Jsoup爬虫HTML数据

    本文参考鸿洋大大的链接详细介绍如何使用Jsoup包抓取HTML数据,是一个纯java工程,并将其打包成jar包.希望了解如何用java语言爬虫网页的可以看下. 杂家前文就又介绍用HTTP访问百度主页得 ...

  8. Dubbo-go 源码笔记(二)客户端调用过程

    作者 | 李志信 导读:有了上一篇文章<Dubbo-go 源码笔记(一)Server 端开启服务过程>的铺垫,可以类比客户端启动于服务端的启动过程.其中最大的区别是服务端通过 zk 注册服 ...

  9. Android添加拍照功能,Android相机开发(二): 给相机加上偏好设置

    Android Camera Develop: add settings to camera app 概述 继上一篇实现了一个最简单的相机APP后,本篇主要介绍实现相机的各种偏好设置,比如分辨率.闪光 ...

最新文章

  1. 不用for 也能实现按照某索引排好某序列
  2. matlab矩阵方块网络着色imshow_matlab中用imshow()显示图像与图像矩阵的数据类型的关系...
  3. python自定义分页器()转自https://www.cnblogs.com/yuanchenqi/articles/7652353.html
  4. android view超出屏幕_Android APP界面保持屏幕常亮方法
  5. exe打包工具哪个最好_为你的 Python 程序写个启动工具箱
  6. linux命令积累之egrep命令
  7. java-图像的几何变换
  8. mysqlfor循环中出错继续_运维大佬教你“打僵尸”——处理Linux系统中大量的僵尸进程(2)...
  9. Hyperledger发布Burrow新版本,改进集成和开发体验
  10. AS1.3 及其以上预览版新插件-实验版(NDK)
  11. 《Python 黑帽子》学习笔记 - 原书 netcat 代码分析 - Day 7
  12. ppt复制切片器_零基础小白自学PPT快速入门到精通(上)
  13. Jquery API帮助文档 chm
  14. 服务器 python cant open file_QQ炫舞转服系统-QQ炫舞官方网站-腾讯游戏
  15. 用userAgent判断手机类型
  16. 记录一次Spring提供的定时任务
  17. 多角度解读新兴公链Sui:团队、架构、代币、生态等
  18. Jenkins SonarQube Quality Gate质量门禁检查
  19. 苹果震荡:曾经的二号人物、薪资最高的奢侈品“女魔头”、零售SVP离职
  20. 「营业日志 2020.12.10」Jiangly 的排列数数题

热门文章

  1. MAS100定位基站
  2. 在医疗保健中使用GIS技术有哪些好处
  3. CSS 使背景色透明但是文字颜色不变
  4. html圣杯布局,圣杯布局方法实例
  5. 【Windows】Word中MathType批量修改公式字体和大小
  6. popuwindow覆盖手机键盘
  7. 测试你的真实性格软件,测试你最真实的性格
  8. 仿知识星球Android源码奉上
  9. 游戏互动营销案例 | 游戏化营销特点
  10. 多声卡同时发声的技术方案