亮度设置
应用设计
1.1 设置进度条范围
背光设置是在:设置->声音和显示->亮度,通过进度条来设置的。
文件:packages/apps/Settings/src/com/android/settings/BrightnessPreference.java
private static final int MINIMUM_BACKLIGHT =
android.os.Power.BRIGHTNESS_DIM + 10;
private static final int MAXIMUM_BACKLIGHT =
android.os.Power.BRIGHTNESS_ON;
mSeekBar.setMax(MAXIMUM_BACKLIGHT - MINIMUM_BACKLIGHT);
设置进度条的范围,BRIGHTNESS_DIM = 20 BRIGHTNESS_ON=255,它们的定义在:
frameworks/base/core/java/android/os/Power.java
1.2 设置亮度
文件:packages/apps/Settings/src/com/android/settings/BrightnessPreference.java
public void onCheckedChanged(CompoundButton buttonView, boolean
isChecked) {
setMode(isChecked ?
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
: Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
if (!isChecked) {
setBrightness(mSeekBar.getProgress() + MINIMUM_BACKLIGHT);
}
}
private void setBrightness(int brightness) {
try {
IPowerManager power = IPowerManager.Stub.asInterface(
ServiceManager.getService("power"));
if (power != null) {
power.setBacklightBrightness(brightness);
}
} catch (RemoteException doe) {
}
}
由以上代码可知,brightness的范围是:20~255;代码通过服务管理器(ServiceManager)获得power服务,然后通过power服务设置亮度。
power.setBacklightBrightness的定义在:
rameworks/base/core/java/android/os/IPowerManager.aidl.java
frameworks/base/core/java/android/os/PowerManager.java
2, Power服务
文件:frameworks/base/core/java/android/os/Power.java
public
static final int BRIGHTNESS_DIM = 20;
public static final int BRIGHTNESS_ON = 255;
文件:frameworks/base/core/java/android/os/PowerManager.java
public void
setBacklightBrightness(int brightness)
{
try {
mService.setBacklightBrightness(brightness);
} catch (RemoteException e) {
}
}
电源管理器(powermager)将brightness转给电源服务,该服务位置如下:
文件:frameworks/base/services/java/com/android/server/PowerManagerService.java
public void setBacklightBrightness(int brightness) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
// Don't let applications turn the screen all the way off
brightness = Math.max(brightness, Power.BRIGHTNESS_DIM);
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
brightness,
HardwareService.BRIGHTNESS_MODE_USER);
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
(mKeyboardVisible ? brightness : 0),
HardwareService.BRIGHTNESS_MODE_USER);
mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
brightness,
HardwareService.BRIGHTNESS_MODE_USER);
long identity = Binder.clearCallingIdentity();
try {
mBatteryStats.noteScreenBrightness(brightness);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException calling noteScreenBrightness on
BatteryStatsService", e);
} finally {
Binder.restoreCallingIdentity(identity);
}
// update our animation state
if (ANIMATE_SCREEN_LIGHTS) {
mScreenBrightness.curValue = brightness;
mScreenBrightness.animating = false;
mScreenBrightness.targetValue = -1;
}
if (ANIMATE_KEYBOARD_LIGHTS) {
mKeyboardBrightness.curValue = brightness;
mKeyboardBrightness.animating = false;
mKeyboardBrightness.targetValue = -1;
}
if (ANIMATE_BUTTON_LIGHTS) {
mButtonBrightness.curValue = brightness;
mButtonBrightness.animating = false;
mButtonBrightness.targetValue = -1;
}
}
由以上代码可知,同时设置了背光、键盘、按钮的亮度。mHardware
是硬件服务,通过该服务调用底层与设备打交道的C\C++代码,setLightBrightness_UNCHECKED原型如下:
文件:frameworks/base/services\java\com\android\server\HardwareService.java
void setLightBrightness_UNCHECKED(int light, int brightness, int
brightnessMode) {
int b = brightness & 0x000000ff;
b = 0xff000000 | (b << 16) | (b
<< 8) | b;
setLight_native(mNativePointer, light, b, LIGHT_FLASH_NONE, 0, 0,
brightnessMode);
}
参数说明:int light 表示类型,选项如下:
static final int LIGHT_ID_BACKLIGHT = 0;
static final
int LIGHT_ID_KEYBOARD = 1;
static final
int LIGHT_ID_BUTTONS = 2;
static final
int LIGHT_ID_BATTERY = 3;
static final
int LIGHT_ID_NOTIFICATIONS = 4;
static final int LIGHT_ID_ATTENTION = 5;
int brightness 表示亮度值
int brightnessMode 表示亮度的控制模式,选项如下:
static final
int BRIGHTNESS_MODE_USER = 0;
static final int BRIGHTNESS_MODE_SENSOR = 1;
由代码:
int b = brightness & 0x000000ff;
b = 0xff000000 | (b << 16) | (b
<< 8) | b;
可知,亮度值在此进行了修改,即亮度值的格式变成:FFRRGGBB,FF是没有的,RR、GG、BB分别是256色的红绿蓝,并且红绿蓝的值都是一样的亮度值。
3 硬件调用
3.1获取硬件
文件:frameworks/base/services/jni/com_android_server_HardwareService.cpp
enum {
LIGHT_INDEX_BACKLIGHT = 0,
LIGHT_INDEX_KEYBOARD = 1,
LIGHT_INDEX_BUTTONS = 2,
LIGHT_INDEX_BATTERY = 3,
LIGHT_INDEX_NOTIFICATIONS = 4,
LIGHT_INDEX_ATTENTION = 5,
LIGHT_COUNT
};
#define LIGHTS_HARDWARE_MODULE_ID "lights"
static jint init_native(JNIEnv *env, jobject clazz)
{
int err;
hw_module_t*
module;
Devices*
devices;
devices =
(Devices*)malloc(sizeof(Devices));
err =
hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t
const**)&module);
if (err ==
0) {
devices->lights[LIGHT_INDEX_BACKLIGHT]
= get_device(module, LIGHT_ID_BACKLIGHT);
devices->lights[LIGHT_INDEX_KEYBOARD]
= get_device(module, LIGHT_ID_KEYBOARD);
devices->lights[LIGHT_INDEX_BUTTONS]
= get_device(module, LIGHT_ID_BUTTONS);
devices->lights[LIGHT_INDEX_BATTERY]
= get_device(module, LIGHT_ID_BATTERY);
devices->lights[LIGHT_INDEX_NOTIFICATIONS]
= get_device(module, LIGHT_ID_NOTIFICATIONS);
devices->lights[LIGHT_INDEX_ATTENTION]
= get_device(module, LIGHT_ID_ATTENTION);
} else {
memset(devices, 0, sizeof(Devices));
}
return
(jint)devices;
}
用hw_get_module获取ID为LIGHTS_HARDWARE_MODULE_ID的硬件模块,该模块含有6个不同类型的亮度控制。
hw_get_module 的实现原理,如下:
文件:hardware/libhardware/Hardware.c
#define HAL_LIBRARY_PATH "/system/lib/hw"
static const char *variant_keys[] = {
"ro.hardware",
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
static const int HAL_VARIANT_KEYS_COUNT =
(sizeof(variant_keys)/sizeof(variant_keys[0]));
int hw_get_module(const char *id, const struct hw_module_t
**module)
{
int
status;
int i;
const struct
hw_module_t *hmi = NULL;
char
prop[PATH_MAX];
char
path[PATH_MAX];
for (i=0 ;
i
if (i < HAL_VARIANT_KEYS_COUNT) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
snprintf(path, sizeof(path), "%s/%s.%s.so",
HAL_LIBRARY_PATH, id, prop);
} else {
snprintf(path, sizeof(path), "%s/%s.default.so",
HAL_LIBRARY_PATH, id);
}
if (access(path, R_OK)) {
continue;
}
break;
}
status =
-ENOENT;
if (i
< HAL_VARIANT_KEYS_COUNT+1) {
status = load(id, path, module);
}
return
status;
}
property_get(variant_keys[i], prop, NULL)
会按如下顺序去获取如下变量所对应的值,然后返回给prop:
"ro.hardware",
"ro.product.board",
"ro.board.platform",
"ro.arch"
它们对应的变量为:
"ro.product.board=$TARGET_BOOTLOADER_BOARD_NAME"
"ro.board.platform=$TARGET_BOARD_PLATFORM"
如vendor/htc/dream-open/BoardConfig.mk里定义的TARGET_BOARD_PLATFORM :=
msm7k,则prop返回” msm7k ”,所以path = /system/lib/hw/lights.
msm7k.so,也就是说要获取的硬件模块为lights. msm7k.so。
3.2调用硬件
setLight_native对应的jni C/C++代码是:
文件:frameworks/base/services/jni/com_android_server_HardwareService.cpp
static void setLight_native(JNIEnv *env, jobject clazz, int
ptr,
int light, int colorARGB, int flashMode, int onMS, int offMS, int
brightnessMode)
{
Devices*
devices = (Devices*)ptr;
light_state_t state;
if (light
< 0 || light >= LIGHT_COUNT ||
devices->lights[light] == NULL) {
return ;
}
memset(&state, 0, sizeof(light_state_t));
state.color
= colorARGB;
state.flashMode = flashMode;
state.flashOnMS = onMS;
state.flashOffMS = offMS;
state.brightnessMode = brightnessMode;
devices->lights[light]->set_light(devices->lights[light],
&state);
}
通过light标识找到对应的light设备,然后再设置亮度。
3.3 硬件原型
msm7k的lights对应的硬件原型是在:hardware/msm7k/liblights
文件:hardware/msm7k/liblights/Android.mk
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM)
也就是生成模块:/system/lib/hw/lights. msm7k.so
文件:hardware/msm7k/liblights/lights.c
static int open_lights(const struct hw_module_t* module, char
const* name,
struct hw_device_t** device)
{
int
(*set_light)(struct light_device_t* dev,
struct light_state_t const* state);
if (0 ==
strcmp(LIGHT_ID_BACKLIGHT, name)) {
set_light = set_light_backlight;
}
else if (0
== strcmp(LIGHT_ID_KEYBOARD, name)) {
set_light = set_light_keyboard;
}
else if (0
== strcmp(LIGHT_ID_BUTTONS, name)) {
set_light = set_light_buttons;
}
else if (0
== strcmp(LIGHT_ID_BATTERY, name)) {
set_light = set_light_battery;
}
else if (0
== strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
set_light = set_light_notifications;
}
else if (0
== strcmp(LIGHT_ID_ATTENTION, name)) {
set_light = set_light_attention;
}
else {
return -EINVAL;
}
pthread_once(&g_init, init_globals);
struct
light_device_t *dev = malloc(sizeof(struct light_device_t));
memset(dev,
0, sizeof(*dev));
dev->common.tag = HARDWARE_DEVICE_TAG;
dev->common.version = 0;
dev->common.module = (struct
hw_module_t*)module;
dev->common.close = (int (*)(struct
hw_device_t*))close_lights;
dev->set_light = set_light;
*device =
(struct hw_device_t*)dev;
return
0;
}
static struct hw_module_methods_t lights_module_methods = {
.open
= open_lights,
};
以上代码对应的是:
devices->lights[LIGHT_INDEX_BACKLIGHT]
= get_device(module, LIGHT_ID_BACKLIGHT);
devices->lights[LIGHT_INDEX_KEYBOARD]
= get_device(module, LIGHT_ID_KEYBOARD);
devices->lights[LIGHT_INDEX_BUTTONS]
= get_device(module, LIGHT_ID_BUTTONS);
devices->lights[LIGHT_INDEX_BATTERY]
= get_device(module, LIGHT_ID_BATTERY);
devices->lights[LIGHT_INDEX_NOTIFICATIONS]
= get_device(module, LIGHT_ID_NOTIFICATIONS);
devices->lights[LIGHT_INDEX_ATTENTION]
= get_device(module, LIGHT_ID_ATTENTION);
也就是说,对不同的亮度设置给予了不同的设置函数。
举例,背光设置,背光对应的代码如下:
char const*const LCD_FILE
= "/sys/class/leds/lcd-backlight/brightness";
static int
rgb_to_brightness(struct light_state_t const* state)
{
int color =
state->color & 0x00ffffff;
return
((77*((color>>16)&0x00ff))
+
(150*((color>>8)&0x00ff))
+ (29*(color&0x00ff)))
>> 8;
}
static int
set_light_backlight(struct light_device_t* dev,
struct light_state_t const* state)
{
int err =
0;
int
brightness = rgb_to_brightness(state);
pthread_mutex_lock(&g_lock);
g_backlight
= brightness;
err =
write_int(LCD_FILE, brightness);
if
(g_haveTrackballLight) {
handle_trackball_light_locked(dev);
}
pthread_mutex_unlock(&g_lock);
return
err;
}
也就是往文件/sys/class/leds/lcd-backlight/brightness写入亮度值,然后驱动会根据该文件更改背光的亮度。LCD_FILE的路径根据实际情况更改,同时需要在init.rc
修改其权限,使其可写rgb_to_brightness也根据实际更改,比如要直接亮度值控制,那只要获取r,g,b其中的一个值就行了,如:
static int
rgb_to_brightness(struct light_state_t const* state)
{
int color =
state->color & 0x000000ff;
return
color;
}
4,led类驱动
4.1,驱动创建leds类,系统启动时执行leds_init在目录/sys/class/创建子目录leds
kernel\drivers\leds\Led-class.c
static int __init leds_init(void)
{
leds_class = class_create(THIS_MODULE,
"leds");
if (IS_ERR(leds_class))
return
PTR_ERR(leds_class);
leds_class->suspend =
led_suspend;
leds_class->resume =
led_resume;
return 0;
}
4.2,led_classdev_register,调用这个函数就在目录/sys/class/leds创建子目录led_cdev->name和属性文件brightness
对brightness文件写就执行led_brightness_store,对brightness文件读就执行led_brightness_show,为下面的lcd,led注册做好准备
kernel\drivers\leds\Led-class.c
static ssize_t led_brightness_show(struct device *dev,struct device_attribute *attr,
char *buf)
{
struct led_classdev *led_cdev =
dev_get_drvdata(dev);
led_update_brightness(led_cdev);
return sprintf(buf, "%u\n",
led_cdev->brightness);
}
static ssize_t led_brightness_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct led_classdev *led_cdev =
dev_get_drvdata(dev);
ssize_t ret = -EINVAL;
char *after;
unsigned long state = simple_strtoul(buf,
&after, 10);
size_t count = after - buf;
if (*after &&
isspace(*after))
count++;
if (count == size) {
ret = count;
if (state == LED_OFF)
led_trigger_remove(led_cdev);
led_set_brightness(led_cdev,
state);
}
return ret;
}
static DEVICE_ATTR(brightness, 0644, led_brightness_show,
led_brightness_store);
int led_classdev_register(struct device *parent, struct
led_classdev *led_cdev)
{
int rc;
led_cdev->dev =
device_create(leds_class, parent, 0, led_cdev,
"%s", led_cdev->name);
if (IS_ERR(led_cdev->dev))
return
PTR_ERR(led_cdev->dev);
rc =
device_create_file(led_cdev->dev,
&dev_attr_brightness);
if (rc)
goto err_out;
#ifdef CONFIG_LEDS_TRIGGERS
init_rwsem(&led_cdev->trigger_lock);
#endif
down_write(&leds_list_lock);
list_add_tail(&led_cdev->node,
&leds_list);
up_write(&leds_list_lock);
led_update_brightness(led_cdev);
#ifdef CONFIG_LEDS_TRIGGERS
rc =
device_create_file(led_cdev->dev,
&dev_attr_trigger);
if (rc)
goto err_out_led_list;
led_trigger_set_default(led_cdev);
#endif
printk(KERN_INFO "Registered led device:
%s\n",
led_cdev->name);
return 0;
#ifdef CONFIG_LEDS_TRIGGERS
err_out_led_list:
device_remove_file(led_cdev->dev,
&dev_attr_brightness);
list_del(&led_cdev->node);
#endif
err_out:
device_unregister(led_cdev->dev);
return rc;
}
EXPORT_SYMBOL_GPL(led_classdev_register);
4.3,lcd驱动调用led_classdev_register,在目录/sys/class/leds创建子目录lcd-backlight和属性文件brightness
kernel\drivers\video\msm\Msm_fb.c
static int lcd_backlight_registered;
static void msm_fb_set_bl_brightness(struct led_classdev
*led_cdev,
enum
led_brightness value)
{
struct msm_fb_data_type *mfd =
dev_get_drvdata(led_cdev->dev->parent);
int bl_lvl;
if (value >
MAX_BACKLIGHT_BRIGHTNESS)
value =
MAX_BACKLIGHT_BRIGHTNESS;
bl_lvl = (2 * value *
mfd->panel_info.bl_max +
MAX_BACKLIGHT_BRIGHTNESS)
/(2 *
MAX_BACKLIGHT_BRIGHTNESS);
if (!bl_lvl &&
value)
bl_lvl = 1;
msm_fb_set_backlight(mfd, bl_lvl, 1);
}
static struct led_classdev backlight_led = {
.name =
"lcd-backlight",
.brightness =
MAX_BACKLIGHT_BRIGHTNESS,
.brightness_set =
msm_fb_set_bl_brightness,
};
if (!lcd_backlight_registered) {
if
(led_classdev_register(&pdev->dev,
&backlight_led))
printk(KERN_ERR
"led_classdev_register failed\n");
else
lcd_backlight_registered
= 1;
}
就在目录/sys/class/leds创建子目录 lcd-backlight和属性文件brightness
当按键或者来的或者改变lcd亮度时,上层对属性文件/sys/class/leds/lcd-backlight/brightness写入背光的亮度数值就
调用led_brightness_store
调用simple_strtoul(buf, &after,
10);将输入的字符串转换为10进制的数字
执行led_set_brightness
执行led_cdev->brightness_set(led_cdev, value
调用msm_fb_set_bl_brightness
,因为 .brightness_set =
msm_fb_set_bl_brightness,
bl_lvl = (2 * value *
mfd->panel_info.bl_max +
MAX_BACKLIGHT_BRIGHTNESS) /(2 *
MAX_BACKLIGHT_BRIGHTNESS);
将输入的0--255转换为IC的0--bl_max
调用 msm_fb_set_backlight(mfd, bl_lvl, 1);
最终改变LCD的背光驱动电路的设置,调节LCD的背光的亮度
4.4 键盘背光灯
上层对属性文件/sys/class/leds/keyboard-backlight/brightness写入背光的亮度数值
(kernel\drivers\leds\Leds-msm-pmic.c
#define MAX_KEYPAD_BL_LEVEL 16
static void msm_keypad_bl_led_set(struct led_classdev
*led_cdev,
enum led_brightness value)
{
int ret;
ret = pmic_set_led_intensity(LED_KEYPAD, value /
MAX_KEYPAD_BL_LEVEL);
if (ret)
dev_err(led_cdev->dev,
"can't set keypad backlight\n");
}
static struct led_classdev msm_kp_bl_led = {
.name =
"keyboard-backlight",
.brightness_set =
msm_keypad_bl_led_set,
.brightness =
LED_OFF,
};
static int msm_pmic_led_probe(struct platform_device *pdev)
{
int rc;
rc =
led_classdev_register(&pdev->dev,
&msm_kp_bl_led);
if (rc) {
dev_err(&pdev->dev,
"unable to register led class driver\n");
return rc;
}
msm_keypad_bl_led_set(&msm_kp_bl_led,
LED_OFF);
return rc;
}
static int __devexit msm_pmic_led_remove(struct platform_device
*pdev)
{
led_classdev_unregister(&msm_kp_bl_led);
return 0;
}
#ifdef CONFIG_PM
static int msm_pmic_led_suspend(struct platform_device *dev,
pm_message_t state)
{
led_classdev_suspend(&msm_kp_bl_led);
return 0;
}
static int msm_pmic_led_resume(struct platform_device *dev)
{
led_classdev_resume(&msm_kp_bl_led);
return 0;
}
#else
#define msm_pmic_led_suspend NULL
#define msm_pmic_led_resume NULL
#endif
static struct platform_driver msm_pmic_led_driver = {
.probe =
msm_pmic_led_probe,
.remove =
__devexit_p(msm_pmic_led_remove),
.suspend =
msm_pmic_led_suspend,
.resume =
msm_pmic_led_resume,
.driver =
{
.name =
"pmic-leds",
.owner =
THIS_MODULE,
},
};
static int __init msm_pmic_led_init(void)
{
return
platform_driver_register(&msm_pmic_led_driver);
}
module_init(msm_pmic_led_init);
static void __exit msm_pmic_led_exit(void)
{
platform_driver_unregister(&msm_pmic_led_driver);
}
module_exit(msm_pmic_led_exit);
MODULE_DESCRIPTION("MSM PMIC LEDs driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:p
系统行动执行msm_pmic_led_init(void)
调用 platform_driver_register(&msm_pmic_led_driver);
调用msm_pmic_led_probe
调用 led_classdev_register(&pdev->dev,
&msm_kp_bl_led);
就在目录/sys/class/leds创建子目录 keyboard-backlight和属性文件brightness
当按键时,上层对属性文件/sys/class/leds/keyboard-backlight/brightness写入背光的亮度数值就
调用led_brightness_store
调用simple_strtoul(buf, &after,
10);将输入的字符串转换为10进制的数字
执行led_set_brightness
执行led_cdev->brightness_set(led_cdev, value
调用msm_keypad_bl_led_set
,因为 .brightness_set =
msm_keypad_bl_led_set,
调用 ret = pmic_set_led_intensity(LED_KEYPAD, value
/ MAX_KEYPAD_BL_LEVEL);
最终改变LED驱动电路的设置,调节LED的亮度