Android Light开发(二) 通知灯调用过程
Android中有各种灯,背光灯,按键灯,指示灯,等等;前几天修改了这部分代码,整理下思路,其实都不难;
首先,来说说指示灯(提示灯),即未接电话,未接短信的时候,会闪灯,这个其实就是NotificationManager这个类中的notify()方法来处理的;流程简单来过一下:
Step 1:从应用层发送的notify(),到framework层被NotificationManager.java这个类接受了,来看看这个notify()这个方法:
- 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) {
- }
- }
重点关注这个enqueueNotificationWithTag()这个方法,这个方法首先会取是否传递过来了声音的Uri,如果传递了,就保存下来,给等会播放用;
Step 2:enqueueNotificationWithTag()这个方法调用到了NotificationManagerService.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<N; 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多行。其中有设计播放声音的地方:
- <span style="font-size:18px;"> player.playAsync(soundUri, user, looping, audioStreamType);</span>
有是否播放震动的地方:
- mVibrator.vibrate(notification.vibrate,
- ((notification.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1);
最后闪灯的地方在这个逻辑中:
- if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
- && canInterrupt) {
- mLights.add(r);
- updateLightsLocked();
- }
重点看updateLightsLocked()这个方法,这个方法里面有逻辑的操作;
Step 3:updateLightsLocked()这个方法的代码如下:
- // 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,或来电的状态,会操作:
- <span style="font-size:18px;">mNotificationLight.turnOff();</span>
下面这个条件也很重要:
- <span style="font-size:18px;">if ((mLedNotification.notification.defaults & Notification.DEFAULT_LIGHTS) != 0) {</span>
未解来电,或短信的时候这个值会设置为
- <span style="font-size:18px;">notification.defaults |= Notification.DEFAULT_LIGHTS;</span>
这个值是4,那么上面的这个判断就为true了,所以灯的颜色就不是由
- <span style="font-size:18px;">mLedNotification.notification.ledARGB;</span>
这个值决定的了,而是由mDefaultNotificationColor这个值决定的,这个值的定义在
- <span style="font-size:18px;">mDefaultNotificationColor = resources.getColor(
- com.android.internal.R.color.config_defaultNotificationColor);</span>
这个值的定义在framework/base/core/res/res/values/config.xml中定义的,
- <span style="font-size:18px;"><color name="config_defaultNotificationColor">#ff0000ff</color></span>
这个表示是蓝灯;具体想改成其他值;
- #ff0000ff 表示蓝灯
- #ff00ff00 表示绿灯
- #ffff0000 表示红灯
后面的逻辑就调用到LightsService.java中去了,这个类是管理灯的类,(背光灯,按键灯,指示灯等等);
拓展:
如果想实现屏幕亮的时候,指示灯灭,屏幕灭的时候指示灯亮;可以监听ACTION_SCREEN_ON/ACTION_SCREEN_OFF的广播,搞一个全局的变量控制下;再调用updateNotificationPulse()这个方法,把变量的判断加载updateNotificationPulse()这个方法的灯亮灭判断的地方即可;
其次,我们来看看返回键的灯,即按键灯;
Step 1 :先来看看PowerManagerService.java这个类。按键灯的定义
- <span style="font-size:18px;"> private LightsService.Light mButtonLight;</span>
初始化方法:
- <span style="font-size:18px;">mButtonLight = mLightsService.getLight(LightsService.LIGHT_ID_BUTTONS);</span>
- <span style="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.");
- }</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开发(二) 通知灯调用过程相关推荐
- Android画板开发(二) 橡皮擦实现
Android画板开发(一) 基本画笔的实现 Android画板开发(二) 橡皮擦实现 Android画板开发(三) 撤销反撤销功能实现 Android画板开发(四) 添加背景和保存画板内容为图片 A ...
- 【Android游戏开发二十七】讲解游戏开发与项目下的hdpi 、mdpi与ldpi资源文件夹以及游戏高清版本的设置...
今天一个开发者问到我为什么游戏开发要删除项目下的hdpi.mdpi和ldpi文件夹:下面详细给大家解答一下: 首先童鞋们如果看过我写的<[Android游戏开发二十一]Android os设备谎 ...
- Android NDK开发: 通过C/C++调用第三方so库
文章目录 一.编写so库代码 二.安装Android NDK 三.编译so库 3.1 编辑Android.mk 3.2 编辑Application.mk 3.3 编译 四.集成到Android工程中 ...
- Android 蓝牙开发(二) --手机与蓝牙音箱配对,并播放音频
Android 蓝牙开发(一) – 传统蓝牙聊天室 Android 蓝牙开发(三) – 低功耗蓝牙开发 项目工程BluetoothDemo 上一章中,我们已经学习了传统蓝牙的开发,这一章,我们来学习如 ...
- 【Android游戏开发二十二】(图文详解)游戏中灵活实现动画播放!简述J2me的游戏类库与Android游戏开发!
本站文章均为 李华明Himi 原创,转载务必在明显处注明:(作者新浪微博: @李华明Himi ) 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/andr ...
- 移动应用开发技术——Android Studio实验二——Activity的调用——竹园摘竹子
掌握线性布局和相对布局的使用方法 掌握基本控件的属性功能及使用方法 掌握Activity的数据回传 通过线性布局和相对布局来搭建两个Activity界面,界面效果如下图所示.当点击"去竹园按 ...
- CSDN Android客户端开发(二):详解如何基于Java用Jsoup爬虫HTML数据
本文参考鸿洋大大的链接详细介绍如何使用Jsoup包抓取HTML数据,是一个纯java工程,并将其打包成jar包.希望了解如何用java语言爬虫网页的可以看下. 杂家前文就又介绍用HTTP访问百度主页得 ...
- Dubbo-go 源码笔记(二)客户端调用过程
作者 | 李志信 导读:有了上一篇文章<Dubbo-go 源码笔记(一)Server 端开启服务过程>的铺垫,可以类比客户端启动于服务端的启动过程.其中最大的区别是服务端通过 zk 注册服 ...
- Android添加拍照功能,Android相机开发(二): 给相机加上偏好设置
Android Camera Develop: add settings to camera app 概述 继上一篇实现了一个最简单的相机APP后,本篇主要介绍实现相机的各种偏好设置,比如分辨率.闪光 ...
最新文章
- 不用for 也能实现按照某索引排好某序列
- matlab矩阵方块网络着色imshow_matlab中用imshow()显示图像与图像矩阵的数据类型的关系...
- python自定义分页器()转自https://www.cnblogs.com/yuanchenqi/articles/7652353.html
- android view超出屏幕_Android APP界面保持屏幕常亮方法
- exe打包工具哪个最好_为你的 Python 程序写个启动工具箱
- linux命令积累之egrep命令
- java-图像的几何变换
- mysqlfor循环中出错继续_运维大佬教你“打僵尸”——处理Linux系统中大量的僵尸进程(2)...
- Hyperledger发布Burrow新版本,改进集成和开发体验
- AS1.3 及其以上预览版新插件-实验版(NDK)
- 《Python 黑帽子》学习笔记 - 原书 netcat 代码分析 - Day 7
- ppt复制切片器_零基础小白自学PPT快速入门到精通(上)
- Jquery API帮助文档 chm
- 服务器 python cant open file_QQ炫舞转服系统-QQ炫舞官方网站-腾讯游戏
- 用userAgent判断手机类型
- 记录一次Spring提供的定时任务
- 多角度解读新兴公链Sui:团队、架构、代币、生态等
- Jenkins SonarQube Quality Gate质量门禁检查
- 苹果震荡:曾经的二号人物、薪资最高的奢侈品“女魔头”、零售SVP离职
- 「营业日志 2020.12.10」Jiangly 的排列数数题