系统介绍

首先别人的APP要能直接访问到你写的硬件或者不经过任何修改的APP能直接使用你的驱动,就需要使用系统自带的JNI,所以我们需要写出符合系统自带JNI文件的HAL文件和驱动程序,下面具体分析一个这个HAL和驱动程序需要实现什么。


灯光系统由以下四个部分组成

APP:电池灯APP,通知灯APP,背光灯APP
JNI :com_android_server_lights_LightsService.cpp
HAL:我们自己实现,实现一个lights.c
驱动:leds_nanopi3.c(JNI需要什么这里就给它提供什么,这里我们实现亮灭闪烁和亮度


灯光系统的主要功能:

硬件上是属于同一个的有(包括颜色和闪烁):
电池灯:电池电量发生变化时颜色会发生变化
通知灯:有通知会闪烁,比如未接电话或短信

调节LCD亮度:
背光灯


驱动部分:

JNI:
com_android_server_lights_LightsService.cpp(不需要我们实现,但我们需要给它提供接口)

里面需要获得hw_module_t结构体,所以我们的HAL需要实现这个结构体

JNI里面的get_device会根据不同的名字调用module->methods->open返回不同的light_device_t结构体,这个结构体里面带有set_light,即不同灯的控制函数。

*********************lights.h*********************

#define LIGHT_ID_BACKLIGHT          "backlight"
#define LIGHT_ID_KEYBOARD           "keyboard"
#define LIGHT_ID_BUTTONS            "buttons"
#define LIGHT_ID_BATTERY            "battery"
#define LIGHT_ID_NOTIFICATIONS      "notifications"
#define LIGHT_ID_ATTENTION          "attention"

这里我们只实现LIGHT_ID_BACKLIGHT(背光)、LIGHT_ID_BATTERY(电池)、LIGHT_ID_NOTIFICATIONS(通知)。

在HAL中的步骤是:
把硬件LED再次划分为不同的逻辑灯

  1. 实现hw_module_t结构体
  2. 实现open函数,它会根据name返回不同的light_device_t结构体
  3. 针对不同的灯(背光/电池/通知),实现对应的set_light函数
struct light_device_t {
    struct hw_device_t common;
    int (*set_light)(struct light_device_t* dev,
            struct light_state_t const* state);
};

这里需实现三个set_light函数

set_light_battery (struct light_device_t *dev, struct light_state_t const* state)
set_light_notifications (struct light_device_t *dev, struct light_state_t const* state)
set_light_backlight (struct light_device_t *dev, struct light_state_t const *state)

通过这些函数里面操作驱动程序。

led_class驱动

1.对灯光的要求

(1)亮度可调节,如背光灯
(2)颜色可变化,如电池电量指示灯
(3)能闪烁,如通知灯

2.Linux内核对led的支持

在Linux内核中已经实现了一个led class, 它里面已经实现了brightness的调节和blink,文件为:drivers/leds/led-class.c
在ledinit()中的led_class_attrs在/sys/class/leds下创建了brightness max_brightness trigger文件。
可以通过以下命令行:
echo 255 > /sys/class/leds/led1/brightness
cat /sys/class/leds/led1/brightness
cat /sys/class/leds/led1/max_brightness

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/leds.h>
 
#include <linux/gpio.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
struct led_desc {
	int gpio;
	char* name;
};

static struct led_desc led_gpios[] = {
	{EXYNOS4212_GPM4(0), "led1"},
	{EXYNOS4212_GPM4(1), "led2"},
	{EXYNOS4212_GPM4(2), "led3"},
	{EXYNOS4212_GPM4(3), "led4"}
};

struct led_classdev_4412 {
	struct led_classdev cdev;
	int gpio;
};
	
static struct led_classdev_4412 *led_devs;
static void brightness_set_4412(struct led_classdev *led_cdev,
              enum led_brightness brightness)
{
	struct led_classdev_4412 *dev = (struct led_classdev_4412*)led_cdev;
	led_cdev->brightness = brightness;
	if (brightness != LED_OFF)
	{
		gpio_set_value(dev->gpio, 0);
	} 
	else {
		gpio_set_value(dev->gpio, 1);
	}
}
int leds_init(void)
{
	int i;
	int ret;
	/* 1.每一个灯分配一个 led_classdev 结构体 */
	/* 2.每一个灯set */
	/* 3.每一个灯 led_classdev_register */
	
	led_devs = kzalloc(sizeof(struct led_classdev_4412) * sizeof(led_gpios)/sizeof(led_gpios[0]), GFP_KERNEL);
	if (led_devs == NULL) {
		printk("NO memory for device\n");
		return -ENOMEM;
	}
	for (i = 0; i < sizeof(led_gpios)/sizeof(led_gpios[0]); i ++) {
		/* 配置成输出引脚        */
		s3c_gpio_cfgpin(led_gpios[i].gpio, S3C_GPIO_OUTPUT);
		/* 先熄灭它 */
		gpio_set_value(led_gpios[i].gpio, 1);
	
		led_devs[i].cdev.max_brightness = LED_FULL;
		led_devs[i].cdev.brightness_set = brightness_set_4412;
		led_devs[i].cdev.flags = LED_CORE_SUSPENDRESUME;
		led_devs[i].cdev.brightness = LED_OFF;
		led_devs[i].cdev.name = led_gpios[i].name;
		led_devs[i].gpio = led_gpios[i].gpio; //设置gpio
		

		ret = led_classdev_register(NULL, &led_devs[i].cdev);
		if (ret) {
			i--; //把已经注册成功的要释放掉
			while(i >= 0) {
			led_classdev_unregister(&led_devs[i].cdev);
			}
			kfree(led_devs);
			return -EIO;
		}
	}
	
	return 0;
}

void leds_exit(void)
{
	int i;
	for (i = 0; i < sizeof(led_gpios)/sizeof(led_gpios[0]); i++) {
		led_classdev_unregister(&led_devs[i]);
	}
	kfree(led_gpios);
}

module_init(leds_init);
module_exit(leds_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wqq Inc.");

将文件放到linux-3.0.86/drivers/leds,并修改linux-3.0.86/drivers/leds/Makefile文件

android 是否打开灯光 安卓照明灯_apache


(2)配置内核

make menuconfig

图形界面如下:

android 是否打开灯光 安卓照明灯_java_02


选中

-> Device Drivers

-> LED Support

[] LED Class Support
[
] LED Trigger support

<*> LED Timer Trigger

(3)开始编译

make zImage

将镜像烧在开发板中,启动后可以看到,会在/sys/class/leds下看到led1——led4

android 是否打开灯光 安卓照明灯_apache_03

4.应用程序设置方法
应用程序是通过sysfs文件来控制led的。

echo 255 > /sys/class/leds/led1/brightness 点亮
echo 0 > /sys/class/leds/led1/brightness 熄灭
echo timmer > /sys/class/leds/led1/trigger ,之后此目录下会多出delay_on/delay_off两个文件
配置它两个可以配置闪烁行为。

闪烁
echo timer > /sys/class/leds/led1/trigger
echo 100 > /sys/class/leds/led1/delay_on //亮100ms
echo 200 > /sys/class/leds/led1/delay_off //灭100ms

分析:
echo timer > /sys/class/leds/led1/trigger
这个会导致led_trigger_store函数调用

//位于\linux-3.0.86-20150324\linux-3.0.86\drivers\leds\led-class.c
static struct device_attribute led_class_attrs[] = {
	__ATTR(brightness, 0644, led_brightness_show, led_brightness_store),
	__ATTR(max_brightness, 0444, led_max_brightness_show, NULL),
#ifdef CONFIG_LEDS_TRIGGERS
	__ATTR(trigger, 0644, led_trigger_show, led_trigger_store),
#endif
	__ATTR_NULL,
};
led_trigger_store // 1. 从trigger_list找出名为"timer"的trigger
	list_for_each_entry(trig, &trigger_list, next_trig) {
		if (!strcmp(trigger_name, trig->name)) {
		    // 2. 调用
		    led_trigger_set(led_cdev, trig);
		        // 3. 把trigger放入led_classdev的trig_list链表里
		        list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
		        led_cdev->trigger = trigger;
		        // 4. 
		        trigger->activate(led_cdev);
		           // 5. 对于"timer"
		           timer_trig_activate
		               // 6. 创建2个文件: delay_on, delay_off
		               device_create_file
		               device_create_file
		               led_blink_set // 让LED闪烁
		               		led_set_software_blink
		               				
		               
		}
	}

// echo 100 > /sys/class/leds/led1/delay_on
led_delay_on_store //位于linux-3.0.86-20150324\linux-3.0.86\drivers\leds\ledtrig-timer.c
  state = simple_strtoul(buf, &after, 10);
	led_blink_set  // // 让LED闪烁
	led_cdev->blink_delay_on = state;

//echo 200 > /sys/class/leds/led1/delay_off //位于linux-3.0.86-20150324\linux-3.0.86\drivers\leds\ledtrig-timer.c
led_delay_off_store
	state = simple_strtoul(buf, &after, 10);
	led_blink_set // 让LED闪烁
	led_cdev->blink_delay_off = state;

编写HAL_lights.c

当有通知或者电量低的时候,灯光会闪烁,要把自己LED驱动结合到安卓系统里

app访问c函数的流程

android 是否打开灯光 安卓照明灯_java_04

JNI文件使用HAL

android 是否打开灯光 安卓照明灯_apache_05


怎么写LIGHTS HAL

a. 实现一个名为HMI的hw_module_t结构体

b. 实现一个open函数, 它会根据name返回一个light_device_t结构体

c. 实现多个light_device_t结构体,每一个对应一个DEVICE

light_device_t结构体里第1个成员是hw_device_t结构体, 紧接着一个set_light函数

参考android-5.0.2/hardware/qcom/display/msm8226/liblight/lights.c
1.新建lights.c文件如下:

/*
 * Copyright (C) 2008 The Android Open Source Project
 * Copyright (C) 2011 Diogo Ferreira <defer@cyanogenmod.com>
 * Copyright (C) 2012 Andreas Makris <andreas.makris@gmail.com>
 * Copyright (C) 2012 The CyanogenMod Project <http://www.cyanogenmod.com>
 *
 * 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_NDEBUG 0
#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 <sys/ioctl.h>
#include <sys/types.h>
#include <hardware/lights.h>

/*以下就是我们linux驱动映射的文件,可以通过将数字写入对应的设备节点,调节亮度和闪烁模式*/
char const*const RED_LED_FILE 			= "/sys/class/leds/led1/brightness";
char const*const GREEN_LED_FILE 		= "/sys/class/leds/led2/brightness";
char const*const BLUE_LED_FILE 			= "/sys/class/leds/led3/brightness";
char const*const RED_LED_FILE_TRIGGER	= "/sys/class/leds/led1/trigger";
char const*const GREEN_LED_FILE_TRIGGER	= "/sys/class/leds/led2/trigger";
char const*const BLUE_LED_FILE_TRIGGER	= "/sys/class/leds/led3/trigger";
char const*const RED_LED_FILE_DELAYON	= "/sys/class/leds/led1/delay_on";
char const*const GREEN_LED_FILE_DELAYON	= "/sys/class/leds/led2/delay_on";
char const*const BLUE_LED_FILE_DELAYON	= "/sys/class/leds/led3/delay_on";
char const*const RED_LED_FILE_DELAYOFF	= "/sys/class/leds/led1/delay_off";
char const*const GREEN_LED_FILE_DELAYOFF= "/sys/class/leds/led2/delay_off";
char const*const BLUE_LED_FILE_DELAYOFF	= "/sys/class/leds/led3/delay_off";
char const*const LCD_BACKLIGHT_FILE     = "/dev/backlight-1wire";

/* Synchronization primities */
static pthread_once_t g_init = PTHREAD_ONCE_INIT;
static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;
/* Mini-led state machine */
static struct light_state_t g_notification;
static struct light_state_t g_battery;


static int write_int (const char *path, int value) {
	int fd;
	static int already_warned = 0;
	fd = open(path, O_RDWR);
	if (fd < 0) {
		if (already_warned == 0) {
			ALOGE("write_int failed to open %s\n", path);
			already_warned = 1;
		}
		return -errno;
	}
	char buffer[20];
	int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
	int written = write (fd, buffer, bytes);
	close(fd);
	return written == -1 ? -errno : 0;
}
static int write_string (const char *path, const char *value) {
	int fd;
	static int already_warned = 0;
	fd = open(path, O_RDWR);
	if (fd < 0) {
		if (already_warned == 0) {
			ALOGE("write_string failed to open %s\n", path);
			already_warned = 1;
		}
		return -errno;
	}
	char buffer[20];
	int bytes = snprintf(buffer, sizeof(buffer), "%s\n", value);
	int written = write (fd, buffer, bytes);
	close(fd);
	return written == -1 ? -errno : 0;
}
/* Color tools */
static int is_lit (struct light_state_t const* state) {
	return state->color & 0x00ffffff;
}
//根据RGB值设置成一个亮度值
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;
}
/* The actual lights controlling section */
====================================================
/*
struct light_state_t {
    unsigned int color;//表示把灯设置成什么颜色或把LCD的亮度设为什么
    int flashMode;//是否闪烁,LIGHT_FLASH_NONE表示不闪
    int flashOnMS;// 亮的时间
    int flashOffMS;// 灭的时间
    int brightnessMode;// 表示LCD的背光亮度模式,有用户模式和感光模式
};
*/
static int set_light_backlight (struct light_device_t *dev, struct light_state_t const *state) {
	int brightness = rgb_to_brightness(state);
	ALOGV("%s brightness=%d color=0x%08x", __func__,brightness,state->color);
	pthread_mutex_lock(&g_lock);

	/* brightness 0-255 */
	/* LCD_BACKLIGHT_FILE�ܽ�����0-127 */
	
	write_int (LCD_BACKLIGHT_FILE, brightness/2);
	
	pthread_mutex_unlock(&g_lock);
	return 0;
}
static void set_shared_light_locked (struct light_device_t *dev, struct light_state_t *state) {
	int r, g, b;
	int delayOn,delayOff;
	r = (state->color >> 16) & 0xFF;
	g = (state->color >> 8) & 0xFF;
	b = (state->color) & 0xFF;
    delayOn = state->flashOnMS;
	delayOff = state->flashOffMS;
	if (state->flashMode != LIGHT_FLASH_NONE) {
		write_string (RED_LED_FILE_TRIGGER, "timer");
		write_string (GREEN_LED_FILE_TRIGGER, "timer");
		write_string (BLUE_LED_FILE_TRIGGER, "timer");
		write_int (RED_LED_FILE_DELAYON, delayOn);
		write_int (GREEN_LED_FILE_DELAYON, delayOn);
		write_int (BLUE_LED_FILE_DELAYON, delayOn);
		write_int (RED_LED_FILE_DELAYOFF, delayOff);
		write_int (GREEN_LED_FILE_DELAYOFF, delayOff);
		write_int (BLUE_LED_FILE_DELAYOFF, delayOff);
	} else {
		write_string (RED_LED_FILE_TRIGGER, "none");
		write_string (GREEN_LED_FILE_TRIGGER, "none");
		write_string (BLUE_LED_FILE_TRIGGER, "none");
	}
	write_int (RED_LED_FILE, r);
	write_int (GREEN_LED_FILE, g);
	write_int (BLUE_LED_FILE, b);
}
static void handle_shared_battery_locked (struct light_device_t *dev) {
	if (is_lit (&g_notification)) {
		set_shared_light_locked (dev, &g_notification);
	} else {
		set_shared_light_locked (dev, &g_battery);
	}
}
static int set_light_battery (struct light_device_t *dev, struct light_state_t const* state) {

	ALOGV("%s flashMode=%d onMS = %d offMS = %d color=0x%08x", __func__,state->flashMode,state->flashOnMS,state->flashOffMS,state->color);

	pthread_mutex_lock (&g_lock);
	g_battery = *state;
	handle_shared_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) {
	ALOGV("%s flashMode=%d onMS = %d offMS = %d color=0x%08x", __func__,state->flashMode,state->flashOnMS,state->flashOffMS,state->color);
	pthread_mutex_lock (&g_lock);
	g_notification = *state;
	handle_shared_battery_locked(dev);
	pthread_mutex_unlock (&g_lock);
	return 0;
}
/* Initializations */
void init_globals () {
	pthread_mutex_init (&g_lock, NULL);
}
/* Glueing boilerplate */
static int close_lights (struct light_device_t *dev) {
	if (dev)
		free(dev);
	return 0;
}
//根据name匹配相应的set_light方法,并返回hw_device_t结构体
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_BATTERY, name)) {
		set_light = set_light_battery;
	}
	else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
		set_light = set_light_notifications;
	}
	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,
};
struct hw_module_t HAL_MODULE_INFO_SYM = {
	.tag = HARDWARE_MODULE_TAG,
	.version_major = 1,
	.version_minor = 0,
	.id = LIGHTS_HARDWARE_MODULE_ID,
	.name = "Sony lights module",
	.author = "Diogo Ferreira <defer@cyanogenmod.com>, Andreas Makris <Andreas.Makris@gmail.com>",
	.methods = &lights_module_methods,
};

2.创建andriod.mk

android 是否打开灯光 安卓照明灯_android_06

把新文件上传到服务器, 所在目录:
hardware/libhardware/modules/lights/lights.c
hardware/libhardware/modules/lights/Android.mk
3.编译

lunch
mmm frameworks/base/services
mmm hardware/libhardware/modules/lights
make snod
./gen-img.sh

framework 灯光系统 – 电池灯源码分析

灯光系统如何调用灯光服务、JNI、HAL等从而操控底层Linux驱动控制的led电池灯去闪烁或者亮不同颜色的灯来通知用户。

不扯别的,直接上图,简单描述整个调用过程:

android 是否打开灯光 安卓照明灯_android_07


以下是详细调用过程:

  1. 首先Android系统加载后会执行init进程,然后加载SystemService.java系统服务。
    \frameworks\base\services\java\com\android\server\SystemServer.java
//位于\frameworks\base\services\java\com\android\server\SystemServer.java
private void startCoreServices() {
    // Manages LEDs and display backlight.
    mSystemServiceManager.startService(LightsService.class);

    // Tracks the battery level.  Requires LightService.
    mSystemServiceManager.startService(BatteryService.class);
}

private void startBootstrapServices() {
    /* 加载电源管理服务,灯光系统属于电源管理的一部分 */
    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
    mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
}

分析mSystemServiceManager.startService方法:

//位于frameworks\base\services\core\java\com\android\server\SystemServiceManager.java
public <T extends SystemService> T startService(Class<T> serviceClass) {
        final String name = serviceClass.getName();
        Slog.i(TAG, "Starting " + name);

        // Create the service.
        if (!SystemService.class.isAssignableFrom(serviceClass)) {
            throw new RuntimeException("Failed to create " + name
                    + ": service must extend " + SystemService.class.getName());
        }
        final T service;
        try {
            Constructor<T> constructor = serviceClass.getConstructor(Context.class);
            service = constructor.newInstance(mContext);//构造了一个服务对象
        } catch (InstantiationException ex) {
         ...
        }
        // Register it.
        //private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
        mServices.add(service);//这里将构造的service,添加到ArrayList<SystemService>中
        // Start it.
        try {
            service.onStart();//调用服务的onStart方法
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + name
                    + ": onStart threw an exception", ex);
        }
        return service;
    }

2 . mSystemServiceManager.startService(LightsService.class);
调用LightsService.java的onStart方法,开启一个LightsManager服务。
LightsManager服务用来管理所有的灯光,包括电池灯、通知灯、背光灯。当需要控制这些灯的时候就需要getLocalService获取这个服务,然后调用这个服务的getLight方法,传入对应的灯的id(参考lighs.h)就可以获取对应的灯的实例化对象,从而可以通过这个对象获取对象里面的操作各种灯的方法。

//\frameworks\base\services\core\java\com\android\server\lights\LightsService.java
public class LightsService extends SystemService {
    static final String TAG = "LightsService";
    static final boolean DEBUG = false;
    //实例化多个LightImpl对象,分别对应电池灯、通知灯、背光灯,通过getLight方法传入不同的id就可以获取对应的对象
    final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
    
//LightImpl继承了Light这个抽象类,并实现了抽象类的setBrightness  setColor  setFlashing等抽象方法,这些方法最终都调用了setLightLocked方法,而setLightLocked方法最终有调用了JNI提供的接口setLight_native

    private final class LightImpl extends Light {

        private LightImpl(int id) {
            mId = id;
        }

        @Override
        public void setBrightness(int brightness) {
            setBrightness(brightness, BRIGHTNESS_MODE_USER);
        }

        @Override
        public void setBrightness(int brightness, int brightnessMode) {
            synchronized (this) {
                int color = brightness & 0x000000ff;
                color = 0xff000000 | (color << 16) | (color << 8) | color;
                setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
            }
        }

        @Override
        public void setColor(int color) {
            synchronized (this) {
                setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
            }
        }

        @Override
        public void setFlashing(int color, int mode, int onMS, int offMS) {
            synchronized (this) {
                setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
            }
        }

        @Override
        public void pulse() {
            pulse(0x00ffffff, 7);
        }

        @Override
        public void pulse(int color, int onMS) {
            synchronized (this) {
                if (mColor == 0 && !mFlashing) {
                    setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER);
                    mColor = 0;
                    mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS);
                }
            }
        }

        @Override
        public void turnOff() {
            synchronized (this) {
                setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
            }
        }

        private void stopFlashing() {
            synchronized (this) {
                setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
            }
        }

        private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
            if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {
                if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
                        + Integer.toHexString(color));
                mColor = color;
                mMode = mode;
                mOnMS = onMS;
                mOffMS = offMS;
                Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
                        + Integer.toHexString(color) + ")");
                try {
                    setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
                }
            }
        }

        private int mId;
        private int mColor;
        private int mMode;
        private int mOnMS;
        private int mOffMS;
        private boolean mFlashing;
    }

    public LightsService(Context context) {
        super(context);

        mNativePointer = init_native();

        for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
            mLights[i] = new LightImpl(i);
        }
    }

    @Override
    public void onStart() {
        publishLocalService(LightsManager.class, mService);
    }

    private final LightsManager mService = new LightsManager() {
        @Override
        public Light getLight(int id) {
            if (id < LIGHT_ID_COUNT) {
                return mLights[id];
            } else {
                return null;
            }
        }
    };

    @Override
    protected void finalize() throws Throwable {
        finalize_native(mNativePointer);
        super.finalize();
    }

    private Handler mH = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            LightImpl light = (LightImpl)msg.obj;
            light.stopFlashing();
        }
    };

    private static native long init_native();
    private static native void finalize_native(long ptr);

    static native void setLight_native(long ptr, int light, int color, int mode,
            int onMS, int offMS, int brightnessMode);

    private long mNativePointer;
}

3.mSystemServiceManager.startService(BatteryService.class);
此时,会调用BatteryService.java的onStart方法。

//位于\frameworks\base\services\core\java\com\android\server\BatteryService.java
BatteryService的构造方法:
public BatteryService(Context context) {
    mHandler = new Handler(true /*async*/);
    /* 获取第2章分析注册的publishLocalService(LightsManager.class, mService);服务 */
    mLed = new Led(context, getLocalService(LightsManager.class));     
}

public Led(Context context, LightsManager lights) {
    /* 获取一个电池灯,后面对电池灯的所以操作都是通过mBatteryLight来进行的 */
    mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
}
public void onStart() {
    IBinder b = ServiceManager.getService("batteryproperties");
    final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =  
    IBatteryPropertiesRegistrar.Stub.asInterface(b);

    /* 注册一个监听器监听电量的变化,电池的Linux驱动上报电池事件时调用batteryPropertiesChanged更新电池灯 */
    batteryPropertiesRegistrar.registerListener(new BatteryListener());

    publishBinderService("battery", new BinderService());
    publishLocalService(BatteryManagerInternal.class, new LocalService());
}

private final class BatteryListener extends IBatteryPropertiesListener.Stub {
    @Override
    public void batteryPropertiesChanged(BatteryProperties props) {
        final long identity = Binder.clearCallingIdentity();
        BatteryService.this.update(props);
        Binder.restoreCallingIdentity(identity);
    }
}

private void update(BatteryProperties props) {
    processValuesLocked(false);
}

private void processValuesLocked(boolean force) {
    /* 发送广播ACTION_BATTERY_CHANGED,通知关心电池状态的进程,低电量提示,关机提示,状态栏图标等
     * 接收广播请看 PowerManagerService.java的BatteryReceiver方法
     */
    sendIntentLocked();

    /* 同时更新电池灯的状态  --  根据电量和是否在充电状态从而使闪灯或者红灯亮或黄灯亮等 */
    mLed.updateLightsLocked();
}

private void sendIntentLocked() {
    //  Pack up the values and broadcast them to everyone
    final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
        }
    });
}

public void updateLightsLocked() {
    final int level = mBatteryProps.batteryLevel;
    final int status = mBatteryProps.batteryStatus;
    /* 如果电量低于警告值的话 */
    if (level < mLowBatteryWarningLevel) {
          /* 如果电量低于警告值,并且正在充电,则将电池灯设置为让低电量颜色的灯亮起,
             如果没有在充电,则让低电量的灯闪烁 */
        if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 
              mBatteryLight.setColor(mBatteryLowARGB);
        } else {
             mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED, 
             mBatteryLedOn, mBatteryLedOff);
        }
    /* 如何电量高于警告值,而且正在充电或者是满电状态,则根据电量选择让不同电量颜色的灯亮起 */
    } else if (status == BatteryManager.BATTERY_STATUS_CHARGING || status == 
            BatteryManager.BATTERY_STATUS_FULL) {
           if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
               mBatteryLight.setColor(mBatteryFullARGB);
           } else {
               mBatteryLight.setColor(mBatteryMediumARGB);
           }
    /* 如果以上状态都不是,则关闭电池灯 */
    } else {
         mBatteryLight.turnOff();
    }
}

3.1 BatteryPropertiesRegistrar服务
我们看看BatteryPropertiesRegistrar.h的定义:
//位于\system\core\healthd\BatteryPropertiesRegistrar.h

.......
namespace android {
 
class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar,
                                   public IBinder::DeathRecipient {
public:
    void publish(const sp<BatteryPropertiesRegistrar>& service);
    void notifyListeners(struct BatteryProperties props);
............
}
 
};  // namespace android

再看看BatteryPropertiesRegistrar.cpp中我们目前关注的函数:
位于\system\core\healthd\BatteryPropertiesRegistrar.cpp

namespace android {
 
void BatteryPropertiesRegistrar::publish(
    const sp<BatteryPropertiesRegistrar>& service) {
    //注册服务到service manager进程
    defaultServiceManager()->addService(String16("batteryproperties"), service);
}
 
void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
    Mutex::Autolock _l(mRegistrationLock);
    for (size_t i = 0; i < mListeners.size(); i++) {
        //通知观察者
        mListeners[i]->batteryPropertiesChanged(props);
    }
}
 
void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
    {
        if (listener == NULL)
            return;
        Mutex::Autolock _l(mRegistrationLock);
        // check whether this is a duplicate
        for (size_t i = 0; i < mListeners.size(); i++) {
            if (IInterface::asBinder(mListeners[i]) == IInterface::asBinder(listener)) {
                return;
            }
        }
 
        //存储观察者
        mListeners.add(listener);
        IInterface::asBinder(listener)->linkToDeath(this);
    }
    //更新底层的电源状态,最终将调用到BatteryMonitor.cpp的update函数
    //也是BatteryService第一次启动,注册Listener后,立马就会更新一次电源信息
    healthd_battery_update();
}
..........
}

我们见过太多对等的Binder通信结构,即双方的主体均在native层,或都在Java层。
这是第一次看到客户端在Java层,服务端在native层。

其实仔细想想,这是完全符合Binder通信架构的。
对于客户端而言,它只需要从service manager进程获取到服务端的BpBinder值,然后利用这个BpBinder值逐步构成Java层的BinderProxy对象(会进一步转化为基于业务的服务代理)。
客户端根本就不要求服务端具有Java层的结构。在实际的通信过程中,客户端数据通过Binder驱动,传到服务端的native层。若native层就能够完成处理过程,就不需要往Java层作进一步的传输,直接返回结果即可。整个处理过程,对于客户端而言,完全是透明的。
3.2 回调接口的作用
我们回过头来看一下BatteryListener的回调接口:

//位于\frameworks\base\services\core\java\com\android\server\BatteryService.java
private final class BatteryListener extends IBatteryPropertiesListener.Stub {
    @Override public void batteryPropertiesChanged(BatteryProperties props) {
        final long identity = Binder.clearCallingIdentity();
        try {
            //电源属性发生变化后,回调BatteryService的update函数
            BatteryService.this.update(props);
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }
}

private void update(BatteryProperties props) {
        synchronized (mLock) {
            if (!mUpdatesStopped) {
                mBatteryProps = props;
                // Process the new values.
                processValuesLocked(false);
            } else {
                mLastBatteryProps.set(props);
            }
        }
    }

private void processValuesLocked(boolean force) {
    /* 发送广播ACTION_BATTERY_CHANGED,通知关心电池状态的进程,低电量提示,关机提示,状态栏图标等
     * 接收广播请看 PowerManagerService.java的BatteryReceiver方法
     */
    sendIntentLocked();

    /* 同时更新电池灯的状态  --  根据电量和是否在充电状态从而使闪灯或者红灯亮或黄灯亮等 */
    mLed.updateLightsLocked();
}

private void sendIntentLocked() {
    //  Pack up the values and broadcast them to everyone
    final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
        }
    });
}

public void updateLightsLocked() {
    final int level = mBatteryProps.batteryLevel;
    final int status = mBatteryProps.batteryStatus;
    /* 如果电量低于警告值的话 */
    if (level < mLowBatteryWarningLevel) {
          /* 如果电量低于警告值,并且正在充电,则将电池灯设置为让低电量颜色的灯亮起,
             如果没有在充电,则让低电量的灯闪烁 */
        if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 
              mBatteryLight.setColor(mBatteryLowARGB);
        } else {
             mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED, 
             mBatteryLedOn, mBatteryLedOff);
        }
    /* 如何电量高于警告值,而且正在充电或者是满电状态,则根据电量选择让不同电量颜色的灯亮起 */
    } else if (status == BatteryManager.BATTERY_STATUS_CHARGING || status == 
            BatteryManager.BATTERY_STATUS_FULL) {
           if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
               mBatteryLight.setColor(mBatteryFullARGB);
           } else {
               mBatteryLight.setColor(mBatteryMediumARGB);
           }
    /* 如果以上状态都不是,则关闭电池灯 */
    } else {
         mBatteryLight.turnOff();
    }
}

看一下广播的接收者,如下:

//位于\frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
		// Register for broadcasts from other components of the system.
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);

private final class BatteryReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            synchronized (mLock) {
                handleBatteryStateChangedLocked();
            }
        }
    }
 
private void handleBatteryStateChangedLocked() {
        mDirty |= DIRTY_BATTERY_STATE;
        updatePowerStateLocked();
    }

通知灯

我们知道,当手机接收到短信的时候,他会发出声音,并且这个通知灯会亮起,那么我们怎么实现呢?一般步骤如下:

1.  getSystemService("NOTIFICATION_SERVICE")
2. 构造notfification
		(1)类别:该次实现类别为通知等
		(2)其他:颜色,OnMS,OffMS。
3. 发出通知

代码如下:

private void FlashingLight()

{
NotificationManager nm = ( NotificationManager ) getSystemService( NOTIFICATION_SERVICE );
//构造通知
Notification notif = new Notification();

notif.flags = Notification.FLAG_SHOW_LIGHTS;

notif.ledARGB = 0xFF0000ff;

notif.ledOnMS = 100;

notif.ledOffMS = 100;
//发出通知

nm.notify(LED_NOTIFICATION_ID, notif);

}

下面我们先分析一下系统中的源码
源码分析
我们打开源码中lights.h文件,可以看到如下:

#define LIGHT_ID_BACKLIGHT          "backlight"
#define LIGHT_ID_KEYBOARD           "keyboard"
#define LIGHT_ID_BUTTONS            "buttons"
#define LIGHT_ID_BATTERY            "battery"
#define LIGHT_ID_NOTIFICATIONS      "notifications"
#define LIGHT_ID_ATTENTION          "attention"
#define LIGHT_ID_BLUETOOTH          "bluetooth"
#define LIGHT_ID_WIFI               "wifi"

然后在源码中搜索LIGHT_ID_NOTIFICATIONS(通知灯),然后找到文件NotificationManagerService.java

//位于\frameworks\base\services\core\java\com\android\server\notification\NotificationManagerService.java
public void onStart() {
...
final LightsManager lights = getLocalService(LightsManager.class);
mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
...
}

和电池灯类似,获得一个对应的Light类型对象,之后所有对通知灯的操作,都是通过mNotificationLight实现,我们还能再改文件中找到一个updateLightsLocked()方法,名字和电池灯中的是一样的,当然内容是不一样的,但是对于通知灯的所有操作都是通过updateLightsLocked()方法实现的,现在我们想知道updateLightsLocked()的调用过程,直接从updateLightsLocked着手是比较困难的。前面提到过,我们编写APP程序时会调用getSystemService(“NOTIFICATION_SERVICE”),那么我们在源码中搜索一下NOTIFICATION_SERVICE,既然有get那么肯定存在类似set的方法,最终我们锁定文件SystemServiceRegistry.java,调用了,以下是一个静态代码块。

//位于frameworks\base\core\java\android\app\SystemServiceRegistry.java
public final class SystemServiceRegistry {
    static {
	    registerService(Context.NOTIFICATION_SERVICE, NotificationManager.class,
                new CachedServiceFetcher<NotificationManager>() {
            @Override
            public NotificationManager createService(ContextImpl ctx) {
                final Context outerContext = ctx.getOuterContext();
                return new NotificationManager(
                    new ContextThemeWrapper(outerContext,
                            Resources.selectSystemTheme(0,
                                    outerContext.getApplicationInfo().targetSdkVersion,
                                    com.android.internal.R.style.Theme_Dialog,
                                    com.android.internal.R.style.Theme_Holo_Dialog,
                                    com.android.internal.R.style.Theme_DeviceDefault_Dialog,
                                    com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
                    ctx.mMainThread.getHandler());
            }});
         }
}

private static <T> void registerService(@NonNull String serviceName,
            @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
        SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
    }
//在这里三个map
// private static final Map<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new ArrayMap<Class<?>, String>();
//    private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new ArrayMap<String, ServiceFetcher<?>>();
//    private static final Map<String, String> SYSTEM_SERVICE_CLASS_NAMES = new ArrayMap<>();

在看看getSystemService方法

public static Object getSystemService(ContextImpl ctx, String name) {
        if (name == null) {
            return null;
        }
        final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        if (fetcher == null) {
            if (sEnableServiceNotFoundWtf) {
                Slog.wtf(TAG, "Unknown manager requested: " + name);
            }
            return null;
        }

        final Object ret = fetcher.getService(ctx);
        if (sEnableServiceNotFoundWtf && ret == null) {
            // Some services do return null in certain situations, so don't do WTF for them.
            switch (name) {
                case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
                case Context.APP_PREDICTION_SERVICE:
                case Context.INCREMENTAL_SERVICE:
                    return null;
            }
            Slog.wtf(TAG, "Manager wrapper not available: " + name);
            return null;
        }
        return ret;
    }

//fetcher.getService(ctx)后
static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;

        CachedServiceFetcher() {
            // Note this class must be instantiated only by the static initializer of the
            // outer class (SystemServiceRegistry), which already does the synchronization,
            // so bare access to sServiceCacheSize is okay here.
            mCacheIndex = sServiceCacheSize++;
        }

        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            final int[] gates = ctx.mServiceInitializationStateArray;
            boolean interrupted = false;

            T ret = null;

            for (;;) {
                boolean doInitialize = false;
                synchronized (cache) {
                    // Return it if we already have a cached instance.
                    T service = (T) cache[mCacheIndex];
                    if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
                        ret = service;
                        break; // exit the for (;;)
                    }

                    // At this point, the gate must be either UNINITIALIZED or INITIALIZING.
                    if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) {
                        doInitialize = true;
                        gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING;
                    }
                }

                if (doInitialize) {
                    // Only the first thread gets here.

                    T service = null;
                    @ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND;
                    try {
                        // This thread is the first one to get here. Instantiate the service
                        // *without* the cache lock held.
                        service = createService(ctx);//这里创建service
                        newState = ContextImpl.STATE_READY;

                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);

                    } finally {
                        synchronized (cache) {
                            cache[mCacheIndex] = service;
                            gates[mCacheIndex] = newState;
                            cache.notifyAll();
                        }
                    }
                    ret = service;
                    break; // exit the for (;;)
                }
                return ret;
       }
       ...
        public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
    }

当调用frameworks\base\core\java\android\app\ContextImpl.java中的如下方法时

final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();

就会触发上述静态块的执行。
综合以上,所以getSystemService返回的是以下registerService方法中的createService中的返回值,如下即new NotificationManager。在使用getSystemService(“NOTIFICATION_SERVICE”),我们获得的是一个NotificationManager实例化的对象。

static {
	    registerService(Context.NOTIFICATION_SERVICE, NotificationManager.class,
                new CachedServiceFetcher<NotificationManager>() {
            @Override
            public NotificationManager createService(ContextImpl ctx) {
                final Context outerContext = ctx.getOuterContext();
                return new NotificationManager(
                    new ContextThemeWrapper(outerContext,
                            Resources.selectSystemTheme(0,
                                    outerContext.getApplicationInfo().targetSdkVersion,
                                    com.android.internal.R.style.Theme_Dialog,
                                    com.android.internal.R.style.Theme_Holo_Dialog,
                                    com.android.internal.R.style.Theme_DeviceDefault_Dialog,
                                    com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
                    ctx.mMainThread.getHandler());
            }});
         }

既然我们获得了NotificationManager的实例化对象,那么我们应该怎么使用呢?我们打开NotificationManager.java文件,
我们找到notify方法,可知最终调用notifyAsUse方法:

//位于frameworks\base\core\java\android\app\NotificationManager.java
 public void notify(String tag, int id, Notification notification)
    {
        int[] idOut = new int[1];
        INotificationManager service = getService();
        String pkg = mContext.getPackageName();
        ...
        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
        Notification stripped = notification.clone();
        Builder.stripForDelivery(stripped);
        try {
            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
               ...
        } catch (RemoteException e) {
        }
    }
//获取一个binder
static public INotificationManager getService()
    {
        if (sService != null) {
            return sService;
        }
        IBinder b = ServiceManager.getService("notification");
        sService = INotificationManager.Stub.asInterface(b);
        return sService;
    }

那么系统中肯定有其他的地方注册了"notification",我们之前提到过SystemServer.java会注册很多的注册方法,我们在其中搜索notification,可以找到

mSystemServiceManager.startService(NotificationManagerService.class);
 //startService会执行mServices.add(service)、service.onStart();

我们查看NotificationManagerService.java文件,当这个类被创建的时候,其中onStart()方法会被调用,该方法最后会调用publishBinderService(Context.NOTIFICATION_SERVICE, mService)。

protected final void publishBinderService(String name, IBinder service,
	            boolean allowIsolated) {
	        ServiceManager.addService(name, service, allowIsolated);
	    }

根据其传入的参数NOTIFICATION_SERVICE = "notification"进行注册。就可以通过使用binder拿到服务对象。
service.enqueueNotificationWithTag(),现在我们回过头来看看enqueueNotificationWithTag()方法:

enqueueNotificationWithTag()
		enqueueNotificationInternal()
			 mHandler.post(new EnqueueNotificationRunnable(userId, r));
			 	EnqueueNotificationRunnable()
			 		run()
			 			 buzzBeepBlinkLocked(r);

最后调用了方法buzzBeepBlinkLocked(),这个方法通过参数r分辨通知是震动,还是声音,或者闪光。在该方法内我们可以找到:

if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
             && ((record.getSuppressedVisualEffects()
             & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
         mLights.add(key);
         updateLightsLocked();
         if (mUseAttentionLight) {
             mAttentionLight.pulse();
         }
         blink = true;
     }

判断通知是否为闪灯,如果为闪灯,则调用 updateLightsLocked(),这样我们分析的就和之前的连系到一起了。

//位于\frameworks\base\services\core\java\com\android\server\notification\NotificationManagerService.java
void updateLightsLocked()
    {
        // handle notification lights
        NotificationRecord ledNotification = null;
        while (ledNotification == null && !mLights.isEmpty()) {
            final String owner = mLights.get(mLights.size() - 1);
            ledNotification = mNotificationsByKey.get(owner);
            if (ledNotification == null) {
                Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
                mLights.remove(owner);
            }
        }

        // Don't flash while we are in a call or screen is on
        if (ledNotification == null || mInCall || mScreenOn) {
            mNotificationLight.turnOff();
            mStatusBar.notificationLightOff();
        } else {
            final Notification ledno = ledNotification.sbn.getNotification();
            int ledARGB = ledno.ledARGB;
            int ledOnMS = ledno.ledOnMS;
            int ledOffMS = ledno.ledOffMS;
            if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
                ledARGB = mDefaultNotificationColor;
                ledOnMS = mDefaultNotificationLedOn;
                ledOffMS = mDefaultNotificationLedOff;
            }
            if (mNotificationPulseEnabled) {
                // pulse repeatedly
                mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
                        ledOnMS, ledOffMS);
            }
            // let SystemUI make an independent decision
            mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
        }
    }

应用程序编写
首先我们打开MainActivity.java文件,可以看到onCreate()方法,该方法会在APP启动的时候调用,那么我们在 class MainActivity中定义一个button如下:

private  Button mLightButton = null;

然后在onCreate()方法中进行实例化,与界面设计的button进行绑定,并且编写其点击方法:

mLightButton = (Button)findViewById(R.id.button);
        mLightButton.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("SetTextI18n")
            public void onClick(View v) {
                // Perform action on click
                flashing = !flashing;
                if (flashing){
                    mLightButton.setText("Stop Flashing the Light");
                }else {
                    mLightButton.setText("Flashing Light at 20S");
                }
                mLightHander.postDelayed(mLightRunnable, 20000);
            }
        });

可以看到我们定义了一个标志位flashing,用来记录是否闪烁的状态,每次点击按钮之后,都会根据标志位的不同,然后显示器对应的字符串。在最后我们开启定时器,那么定时器在java中是怎么使用的呢?我们需要定义一个class Handle。这个handler中并没有绑定新线程,所以还是次线程处理消息事件,即2s后处理。

private Handler mLightHander = new Handler();
private LightRunnable mLightRunnable = new LightRunnable();
class LightRunnable implements Runnable {
        @Override
        public void run() {
            if(flashing) {
                FlashingLight();
            }else{
                ClearLED();
            }
	    }
    }

该接口需要实现一个方法,该方法就是定时时间到,然后执行的函数,可以看到在其中我们调用了两个方法,分别为 FlashingLight(),ClearLED()。其中FlashingLight()的实现如下:

private void FlashingLight()
    {
        NotificationManager nm = ( NotificationManager ) getSystemService( NOTIFICATION_SERVICE );
        Notification notif = new Notification();
        notif.flags = Notification.FLAG_SHOW_LIGHTS;
        notif.ledARGB = 0xFF0000ff;
        notif.ledOnMS = 100;
        notif.ledOffMS = 100;
        nm.notify(LED_NOTIFICATION_ID, notif);
    }

private void ClearLED()
    {
        NotificationManager nm = ( NotificationManager ) getSystemService( NOTIFICATION_SERVICE );
        nm.cancel(LED_NOTIFICATION_ID);
    }