Android lighting system (battery light / notification light)

System introduction

First of all, if other people's apps can directly access the hardware you write or directly use your driver without any modification, they need to use the JNI that comes with the system. Therefore, we need to write HAL files and drivers that meet the JNI files that come with the system. The following is a specific analysis of what this HAL and driver need to achieve.

The lighting system consists of the following four parts

APP: battery lamp APP, notification lamp APP, backlight lamp APP
JNI : com_android_server_lights_LightsService.cpp
HAL: we implement it ourselves and implement a lights c
Drive: leds_nanopi3.c (JNI can provide it with whatever it needs. Here we realize on-off flicker and brightness

Main functions of lighting system:

The hardware belongs to the same (including color and flicker):
Battery lamp: the color will change when the battery power changes
Notification light: when there is a notification, it will flash, such as missed call or short message

Adjust LCD brightness:
Backlight

Drive part:

JNI:
com_ android_ server_ lights_ LightsService. CPP (we don't need to implement it, but we need to provide it with an interface)

You need to get HW inside_ module_ T structure, so our HAL needs to implement this structure

Get in JNI_ Device will call module - > methods - > open according to different names and return different lights_ device_ T structure with set inside_ Light, that is, the control function of different lights.

*********************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"

Here we only realize light_ ID_ Backlight, light_ ID_ Battery, light_ ID_ Notifications.

The steps in HAL are:
The hardware LED is divided into different logic lights again

  1. Implement hw_module_t structure
  2. Implement the open function, which will return different lights according to the name_ device_ T structure
  3. For different lights (backlight / battery / notification), realize the corresponding set_light function
struct light_device_t {
    struct hw_device_t common;
    int (*set_light)(struct light_device_t* dev,
            struct light_state_t const* state);
};

Three sets need to be implemented here_ Light function

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)

Operate the driver through these functions.

led_class driver

1. Requirements for lighting

(1) Adjustable brightness, such as backlight
(2) The color can be changed, such as battery power indicator
(3) Can flash, such as a notification light

2.Linux kernel support for led

An led class has been implemented in the Linux kernel, which has realized the adjustment and blink of brightness. The file is drivers / LEDs / led class c
Led in ledinit()_ class_ Attrs creates brightness Max under / sys/class/leds_ Brightness trigger file.
You can use the following command line:
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.Each lamp is assigned an led_classdev structure */
	/* 2.Each light set */
	/* 3.Each 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 ++) {
		/* Configure as output pin        */
		s3c_gpio_cfgpin(led_gpios[i].gpio, S3C_GPIO_OUTPUT);
		/* Put it out first */
		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; //Set gpio
		

		ret = led_classdev_register(NULL, &led_devs[i].cdev);
		if (ret) {
			i--; //Release those who have registered successfully
			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.");

Put the file into linux-3.0.86/drivers/leds, and modify the linux-3.0.86/drivers/leds/Makefile file

(2) Configure kernel

make menuconfig

The graphical interface is as follows:

Select
-> Device Drivers
-> LED Support
[] LED Class Support
[] LED Trigger support
<*> LED Timer Trigger
(3) Start compilation

make zImage

Burn the image in the development board. After startup, you can see led1 -- led4 under / sys/class/leds

4. Application setting method
The application program controls the led through the sysfs file.

Echo 255 > / sys / class / LEDs / LED1 / brightness on
Echo 0 > / sys / class / LEDs / LED1 / brightness off
Echo timer > / sys / class / LEDs / LED1 / trigger, and then there will be more delay in this directory_ on/delay_ Off two files
Configure both of them to configure flicker behavior.

twinkle
echo timer > /sys/class/leds/led1/trigger
echo 100 > /sys/class/leds/led1/delay_on //Light for 100ms
echo 200 > /sys/class/leds/led1/delay_off //Extinguish for 100ms

analysis:
echo timer > /sys/class/leds/led1/trigger
This can lead to_ trigger_ Store function call

//Located at \ 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. From trigger_list find a trigger named "timer"
	list_for_each_entry(trig, &trigger_list, next_trig) {
		if (!strcmp(trigger_name, trig->name)) {
		    // 2. Call
		    led_trigger_set(led_cdev, trig);
		        // 3. Put the trigger into the LED_ Trig of classdev_ List list
		        list_add_tail(&led_cdev->trig_list, &trigger->led_cdevs);
		        led_cdev->trigger = trigger;
		        // 4. 
		        trigger->activate(led_cdev);
		           // 5. For "timer"
		           timer_trig_activate
		               // 6. Create 2 files: delay_on, delay_off
		               device_create_file
		               device_create_file
		               led_blink_set // Let the LED flash
		               		led_set_software_blink
		               				
		               
		}
	}

// echo 100 > /sys/class/leds/led1/delay_on
led_delay_on_store //Located at linux-3.0.86-20150324 \ linux-3.0.86 \ drivers \ LEDs \ ledrig timer c
  state = simple_strtoul(buf, &after, 10);
	led_blink_set  // //Let the LED flash
	led_cdev->blink_delay_on = state;

//echo 200 > /sys/class/leds/led1/delay_ Off / / located in linux-3.0.86-20150324 \ linux-3.0.86 \ drivers \ LEDs \ ledrig timer c
led_delay_off_store
	state = simple_strtoul(buf, &after, 10);
	led_blink_set // Let the LED flash
	led_cdev->blink_delay_off = state;

Prepare HAL_lights.c

When there is a notification or the power is low, the light will flash. You should integrate your LED driver into the Android system
Process of app accessing c function

JNI files use HAL

How to write LIGHTS HAL
a. Implement a HW called HMI_ module_ T structure
b. Implement an open function, which will return a light according to the name_ device_ T structure
c. Implement multiple lights_ DEVICE_ T structure, each corresponding to a DEVICE
light_ device_ The first member in the T structure is hw_device_t structure, followed by a set_light function

Refer to android-5.0.2/hardware/qcom/display/msm8226/liblight/lights c
1. Create new lights C the documents are as follows:

/*
 * 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>

/*The following is our linux driver mapping file. You can adjust the brightness and flicker mode by writing the number to the corresponding device node*/
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;
}
//Set to a brightness value according to the RGB value
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;//Indicates what color the light is set to or why the brightness of the LCD is set
    int flashMode;//Is it flashing, LIGHT_FLASH_NONE means no flashing
    int flashOnMS;// Light up time
    int flashOffMS;// Time of extinction
    int brightnessMode;// Indicates the backlight brightness mode of LCD, including user mode and photosensitive mode
};
*/
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;
}
//Match the corresponding set according to the name_ Light method and returns hw_device_t structure
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. Create Android mk

Upload the new file to the server in the following directory:
hardware/libhardware/modules/lights/lights.c
hardware/libhardware/modules/lights/Android.mk
3. Compilation

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

framework lighting system - battery lamp source code analysis

How does the lighting system call lighting services, JNI, HAL, etc., so as to control the led battery lamp controlled by the underlying Linux driver to flash or light different colors to inform users.
Let's go directly to the figure above and briefly describe the whole calling process:

The following is a detailed call procedure:

  1. First, the Android system will execute the init process after loading, and then load systemservice Java system services.
    \frameworks\base\services\java\com\android\server\SystemServer.java
//Located at \ 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() {
    /* Load the power management service, and the lighting system is part of the power management */
    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
    mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
}

Analyze msystemservicemanager Startservice method:

//Located at 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);//A service object is constructed
        } catch (InstantiationException ex) {
         ...
        }
        // Register it.
        //private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
        mServices.add(service);//Here, add the constructed service to ArrayList < systemservice >
        // Start it.
        try {
            service.onStart();//Call the onStart method of the service
        } catch (RuntimeException ex) {
            throw new RuntimeException("Failed to start service " + name
                    + ": onStart threw an exception", ex);
        }
        return service;
    }

2 . mSystemServiceManager.startService(LightsService.class);
Call lightsservice The onStart method of Java starts a LightsManager service.
LightsManager service is used to manage all lights, including battery lights, notification lights and backlights. When you need to control these lights, you need getLocalService to get the service, then call the getLight method of the service, and pass the corresponding id of the lamp (reference lighs.h) to get the corresponding instantiated object of the lamp, so that you can get the method of operating all kinds of lights in the object through this object.

//\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;
    //Instantiate multiple LightImpl objects corresponding to battery lamp, notification lamp and backlight respectively. You can obtain the corresponding objects by passing in different IDS through the getLight method
    final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];
    
//LightImpl inherits the abstract class of Light and implements the abstract methods such as setbrightness, SetColor and setflashing of the abstract class. These methods finally call the setLightLocked method, and the setLightLocked method finally calls the interface SetLight provided by JNI_ 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);
At this point, batteryservice. Is called onStart method of Java.

//Located at \ frameworks \ base \ services \ core \ Java \ com \ Android \ server \ batteryservice java
BatteryService Construction method:
public BatteryService(Context context) {
    mHandler = new Handler(true /*async*/);
    /* Obtain the publishLocalService(LightsManager.class, mService) registered in Chapter 2; service */
    mLed = new Led(context, getLocalService(LightsManager.class));     
}

public Led(Context context, LightsManager lights) {
    /* Get a battery lamp. All operations on the battery lamp are carried out through mBatteryLight */
    mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
}
public void onStart() {
    IBinder b = ServiceManager.getService("batteryproperties");
    final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =  
    IBatteryPropertiesRegistrar.Stub.asInterface(b);

    /* Register a listener to monitor the change of power. When the Linux driver of the battery reports a battery event, call batteryPropertiesChanged to update the battery light */
    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) {
    /* Send broadcast ACTION_BATTERY_CHANGED, notify the process of caring about the battery status, low battery prompt, shutdown prompt, status bar icon, etc
     * See powermanagerservice.com for receiving broadcast BatteryReceiver method of Java
     */
    sendIntentLocked();

    /* At the same time, update the status of the battery light -- make the flashing light or red light or yellow light on according to the power and whether it is in the charging state */
    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 the charge is lower than the warning value */
    if (level < mLowBatteryWarningLevel) {
          /* If the battery level is lower than the warning value and is charging, set the battery light to light the light in the low battery color,
             If you are not charging, let the low battery light flash */
        if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 
              mBatteryLight.setColor(mBatteryLowARGB);
        } else {
             mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED, 
             mBatteryLedOn, mBatteryLedOff);
        }
    /* If the power level is higher than the warning value and is being charged or fully charged, select the lights with different power colors to light up according to the power level */
    } 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);
           }
    /* If none of the above states is true, turn off the battery light */
    } else {
         mBatteryLight.turnOff();
    }
}

3.1 BatteryPropertiesRegistrar service
Let's look at batterypropertiesregistrar Definition of H:
//Located at \ 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

Take another look at batterypropertiesregistrar In CPP, we focus on the following functions:
Located at \ system \ core \ Healthd \ batterypropertiesregistrar cpp

namespace android {
 
void BatteryPropertiesRegistrar::publish(
    const sp<BatteryPropertiesRegistrar>& service) {
    //Register the service to the service manager process
    defaultServiceManager()->addService(String16("batteryproperties"), service);
}
 
void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
    Mutex::Autolock _l(mRegistrationLock);
    for (size_t i = 0; i < mListeners.size(); i++) {
        //Notify the observer
        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;
            }
        }
 
        //Storage observer
        mListeners.add(listener);
        IInterface::asBinder(listener)->linkToDeath(this);
    }
    //Update the underlying power status, and eventually call batterymonitor CPP update function
    //It is also the first time that BatteryService is started. After registering the Listener, the power information will be updated immediately
    healthd_battery_update();
}
..........
}

We have seen too many peer-to-peer Binder communication structures, that is, the subjects of both sides are in the native layer or in the Java layer.
This is the first time to see that the client is in the Java layer and the server is in the native layer.

In fact, when you think about it, it is completely in line with Binder's communication architecture.
For the client, it only needs to obtain the BpBinder value of the server from the service manager process, and then use this BpBinder value to gradually form the BinderProxy object of the Java layer (which will be further transformed into a business based service proxy).
The client does not require the server to have a Java layer structure at all. In the actual communication process, the client data is transmitted to the native layer of the server through Binder driver. If the native layer can complete the processing process, there is no need to make further transmission to the Java layer and return the results directly. The whole process is completely transparent to the client.
3.2 function of callback interface
Let's look back at the callback interface of BatteryListener:

//Located at \ 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 {
            //Call back the update function of BatteryService after the power attribute changes
            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) {
    /* Send broadcast ACTION_BATTERY_CHANGED, notify the process of caring about the battery status, low battery prompt, shutdown prompt, status bar icon, etc
     * See powermanagerservice.com for receiving broadcast BatteryReceiver method of Java
     */
    sendIntentLocked();

    /* At the same time, update the status of the battery light -- make the flashing light or red light or yellow light on according to the power and whether it is in the charging state */
    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 the charge is lower than the warning value */
    if (level < mLowBatteryWarningLevel) {
          /* If the battery level is lower than the warning value and is charging, set the battery light to light the light in the low battery color,
             If you are not charging, let the low battery light flash */
        if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 
              mBatteryLight.setColor(mBatteryLowARGB);
        } else {
             mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED, 
             mBatteryLedOn, mBatteryLedOff);
        }
    /* If the power level is higher than the warning value and is being charged or fully charged, select the lights with different power colors to light up according to the power level */
    } 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);
           }
    /* If none of the above states is true, turn off the battery light */
    } else {
         mBatteryLight.turnOff();
    }
}

Take a look at the receiver of the broadcast, as follows:

//Located at \ 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();
    }

Notification light

We know that when the mobile phone receives a text message, it will make a sound and the notification light will light up. So how can we achieve it? The general steps are as follows:

1.  getSystemService("NOTIFICATION_SERVICE")
2. structure notfification
		(1)Category: this implementation category is notification, etc
		(2)Others: color, OnMS,OffMS. 
3. give an announcement

The code is as follows:

private void FlashingLight()

{
NotificationManager nm = ( NotificationManager ) getSystemService( NOTIFICATION_SERVICE );
//Construction notice
Notification notif = new Notification();

notif.flags = Notification.FLAG_SHOW_LIGHTS;

notif.ledARGB = 0xFF0000ff;

notif.ledOnMS = 100;

notif.ledOffMS = 100;
//give an announcement

nm.notify(LED_NOTIFICATION_ID, notif);

}

Let's first analyze the source code in the system
Source code analysis
We open the source of lights H file, you can see the following:

#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"

Then search for light in the source code_ ID_ Notifications and locate the file notificationmanagerservice java

//Located at \ 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);
...
}

Similar to the battery lamp, get a corresponding Light type object, and then all operations on the notification lamp are implemented through mNotificationLight. We can also find an updateLightsLocked() method in the file. The name is the same as that in the battery lamp. Of course, the content is different, but all operations on the notification lamp are implemented through updateLightsLocked() method, Now we want to know the calling process of updateLightsLocked (). It is difficult to start directly from updateLightsLocked. As mentioned earlier, when we write the APP program, we will call getSystemService ("NOTIFICATION_SERVICE"), so let's search for notification in the source code_ Service, since there is get, there must be a method similar to set. Finally, we lock the file systemserviceregistry Java, called. The following is a static code block.

//Located in 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());
    }
//Here are three map s
// 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<>();

Look at the getSystemService method

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. After 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);//Create a service here
                        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;
    }

When calling frameworks \ base \ core \ Java \ Android \ app \ contextimpl When using the following methods in Java

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

The execution of the above static block will be triggered.
Based on the above, getSystemService returns the return value of createService in the following registerService method, as follows: new NotificationManager. When using getSystemService ("NOTIFICATION_SERVICE"), we get an object instantiated by 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());
            }});
         }

Now that we have the instantiated object of NotificationManager, how should we use it? We open NotificationManager Java files,
We find the notify method, and we can see that the notifyAsUse method is finally called:

//Located in 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) {
        }
    }
//Get a binder
static public INotificationManager getService()
    {
        if (sService != null) {
            return sService;
        }
        IBinder b = ServiceManager.getService("notification");
        sService = INotificationManager.Stub.asInterface(b);
        return sService;
    }

Then there must be other places in the system that have registered "notification". We mentioned systemserver Java will register many registration methods. We can find them by searching notification

mSystemServiceManager.startService(NotificationManagerService.class);
 //startService will execute mservices add(service),service.onStart();

Let's look at notificationmanagerservice Java file. When this class is created, the onStart() method will be called, and this method will finally call publishBinderService(Context.NOTIFICATION_SERVICE, mService).

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

Based on its passed in parameter NOTIFICATION_SERVICE = "notification" to register. You can get the service object by using the binder.
service.enqueueNotificationWithTag(), now let's look back at the enqueueNotificationWithTag() method:

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

Finally, the method called buzzBeepBlinkLocked() is invoked. This method determines whether the notification is vibration, sound or flash through the parameter r. In this method, we can find:

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;
     }

Judge whether the notification is flashing. If it is flashing, call updateLightsLocked(), so that our analysis is connected with the previous one.

//Located at \ 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);
        }
    }

Application programming
First, let's open mainactivity Java file, you can see the onCreate() method, which will be called when the APP starts. Then we define a button in class MainActivity as follows:

private  Button mLightButton = null;

Then instantiate it in onCreate() method, bind it to the button of interface design, and write its click method:

 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);
            }
        });

We can see that we have defined a flag bit flashing, which is used to record whether it flashes. After each click of the button, we will display the corresponding string according to the different flag bits. In the end, we start the timer. How is the timer used in java? We need to define a class Handle. There is no new thread bound in this handler, so it is still a secondary thread to process message events, that is, 2s post-processing.

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

The interface needs to implement a method. This method is the function to execute when the timing time is up. You can see that we call two methods, namely FlashingLight(), ClearLED(). The implementation of flashinglight () is as follows:

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);
    }

Tags: Java Android Apache

Posted by brodywx on Fri, 01 Apr 2022 18:50:28 +0300