private void RedFlashLight()
{
NotificationManager nm = ( NotificationManager ) getSystemService( NOTIFICATION_SERVICE );
Notification notif = new Notification();
notif.ledARGB = 0xFFff0000;
notif.flags = Notification.FLAG_SHOW_LIGHTS;
notif.ledOnMS = 100;
notif.ledOffMS = 100;
nm.notify(LED_NOTIFICATION_ID, notif);
}
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) {
- }
- }
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;
- }
- <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();
- }
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>
- <span style="font-size:18px;">mLedNotification.notification.ledARGB;</span>
- <span style="font-size:18px;">mDefaultNotificationColor = resources.getColor(
- com.android.internal.R.color.config_defaultNotificationColor);</span>
- <span style="font-size:18px;"><color name="config_defaultNotificationColor">#ff0000ff</color></span>
- #ff0000ff 表示蓝灯
- #ff00ff00 表示绿灯
- #ffff0000 表示红灯
拓展:
如果想实现屏幕亮的时候,指示灯灭,屏幕灭的时候指示灯亮;可以监听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>
灯关闭的方法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 mutex
- pthread_mutex_init(&g_lock, NULL);
- // figure out if we have the trackball LED or not
- g_haveTrackballLight = (access(TRACKBALL_FILE, W_OK) == 0) ? 1 : 0;
- }
- static int
- write_int(char const* path, int value)
- {
- int fd;
- #ifdef LIGHTS_INFO_ON
- ALOGD("write %d to %s", value, path);
- #endif
- fd = 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_ON
- ALOGD("write %s to %s", str, path);
- #endif
- fd = 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 blink
- int nowStatus;
- int i = 0;
- if (level == 0)
- nowStatus = 0;
- else if (onMS && offMS)
- nowStatus = 1;
- else
- nowStatus = 2;
- if (preStatus == nowStatus)
- return -1;
- #ifdef LIGHTS_DBG_ON
- ALOGD("blink_red, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
- #endif
- if (nowStatus == 0) {
- write_int(RED_LED_FILE, 0);
- }
- else if (nowStatus == 1) {
- // write_int(RED_LED_FILE, level); // default full brightness
- write_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 fs
- i++;
- }
- 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 blink
- int nowStatus;
- int i = 0;
- if (level == 0)
- nowStatus = 0;
- else if (onMS && offMS)
- nowStatus = 1;
- else
- nowStatus = 2;
- if (preStatus == nowStatus)
- return -1;
- #ifdef LIGHTS_DBG_ON
- ALOGD("blink_green, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
- #endif
- if (nowStatus == 0) {
- write_int(GREEN_LED_FILE, 0);
- }
- else if (nowStatus == 1) {
- // write_int(GREEN_LED_FILE, level); // default full brightness
- write_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 fs
- i++;
- }
- 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 blink
- int nowStatus;
- int i = 0;
- if (level == 0)
- nowStatus = 0;
- else if (onMS && offMS)
- nowStatus = 1;
- else
- nowStatus = 2;
- if (preStatus == nowStatus)
- return -1;
- #ifdef LIGHTS_DBG_ON
- ALOGD("blink_blue, level=%d, onMS=%d, offMS=%d\n", level, onMS, offMS);
- #endif
- if (nowStatus == 0) {
- write_int(BLUE_LED_FILE, 0);
- }
- else if (nowStatus == 1) {
- // write_int(BLUE_LED_FILE, level); // default full brightness
- write_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 fs
- i++;
- }
- 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_ON
- ALOGD("set_led_state colorRGB=%08X, onMS=%d, offMS=%d\n",
- colorRGB, onMS, offMS);
- #endif
- alpha = (colorRGB >> 24) & 0xFF;
- if (alpha) {
- red = (colorRGB >> 16) & 0xFF;
- green = (colorRGB >> 8) & 0xFF;
- blue = colorRGB & 0xFF;
- } else { // alpha = 0 means turn the LED off
- red = 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,
- };