Android 通知灯设置

Posted 虫师魁拔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 通知灯设置相关的知识,希望对你有一定的参考价值。

  系统通知灯相关文件

 frameworks/base/services/core/java/com/android/server/lights/LightsManager.java 

 frameworks/base/services/core/java/com/android/server/lights/LogicalLight.java

 frameworks/base/services/core/java/com/android/server/lights/LightsService.java

 frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp

 hardware/interfaces/light/2.0/default/Light.cpp

 hardware/qcom/display/liblight/lights.c 

一、LightsManager.java 

主要定义各种灯类型和一个 getLight 抽象函数

public abstract class LightsManager 
    public static final int LIGHT_ID_BACKLIGHT = Type.BACKLIGHT; //背光灯
    public static final int LIGHT_ID_KEYBOARD = Type.KEYBOARD; //键盘灯
    public static final int LIGHT_ID_BUTTONS = Type.BUTTONS; //按键灯
    public static final int LIGHT_ID_BATTERY = Type.BATTERY; //电池指示灯
    public static final int LIGHT_ID_NOTIFICATIONS = Type.NOTIFICATIONS; //通知灯
    public static final int LIGHT_ID_ATTENTION = Type.ATTENTION; //重要灯
    public static final int LIGHT_ID_BLUETOOTH = Type.BLUETOOTH; //蓝牙
    public static final int LIGHT_ID_WIFI = Type.WIFI; //WIFI灯
    public static final int LIGHT_ID_COUNT = Type.COUNT; //这个表示灯类型数量

    public abstract LogicalLight getLight(int id);

二、LogicalLight.java

定义调用接口,供系统使用,其实现在 LightsService$LightImpl 中

三、LightsService.java

系统服务,实际实现led控制功能,往下调用 jni native函数

    @Override
    public void onStart() 
        publishLocalService(LightsManager.class, mService);
        publishBinderService(Context.LIGHTS_SERVICE, mManagerService);
    

    ... ...

    private final LightsManager mService = new LightsManager() 
        @Override
        public LogicalLight getLight(int lightType) 
            if (mLightsByType != null && 0 <= lightType && lightType < mLightsByType.length) 
                return mLightsByType[lightType];
             else 
                return null;
            
        
    ;

 内部主要是使用一个 LightsService$LightImpl(LogicalLight 实现类)数组 mLightsByType ,保存所有类型灯的对象,通过 getSystemService 获取 LightsManager 需要根据不同灯的类型去获取对应的对象。

LightImpl 中是所有led相关操作上层接口的实现,例如设置灯打开、关闭、颜色、亮度、闪烁等。

        @Override
        public void setColor(int color) 
            synchronized (this) 
                // 设置颜色灯是常亮的,使用 LIGHT_FLASH_NONE
                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);
            
        

mode 有三种:

/**
 * 常亮或者常灭
 */
public static final int LIGHT_FLASH_NONE = Flash.NONE;

/**
 * 以指定的速率闪烁灯光
 */
public static final int LIGHT_FLASH_TIMED = Flash.TIMED;

/**
 * 使用硬件辅助闪烁指示灯,闪烁时间一般是固定
 */
public static final int LIGHT_FLASH_HARDWARE = Flash.HARDWARE;

四、com_android_server_lights_LightsService.cpp

系统 jni 层,调用 HIDL 服务端接口

Return<Status> ret = hal->setLight(type, state);

五、hardware/interfaces/light/2.0/default/Light.cpp 

HIDL 服务端接口,继续调用系统的 HAL 库函数

Return<Status> Light::setLight(Type type, const LightState& state)  
    auto it = mLights.find(type);
    if (it == mLights.end()) 
        return Status::LIGHT_NOT_SUPPORTED;
    
    light_device_t* hwLight = it->second;
    light_state_t legacyState 
        .color = state.color,
        .flashMode = static_cast<int>(state.flashMode),
        .flashOnMS = state.flashOnMs,
        .flashOffMS = state.flashOffMs,
        .brightnessMode = static_cast<int>(state.brightnessMode),
    ;
    int ret = hwLight->set_light(hwLight, &legacyState);
    switch (ret) 
        case -ENOSYS:
            return Status::BRIGHTNESS_NOT_SUPPORTED;
        case 0:
            return Status::SUCCESS;
        default:
            return Status::UNKNOWN;
    

mLights 也是根据不同的灯 id 类型保存了一个数组 

六、hardware/qcom/display/liblight/lights.c

系统的 HAL 库代码文件,直接操作系统节点,实现 led 控制

static int
set_light_battery(struct light_device_t* dev,
        struct light_state_t const* state)

    pthread_mutex_lock(&g_lock);
    g_battery = *state;
    handle_speaker_battery_locked(dev);
    pthread_mutex_unlock(&g_lock);
    return 0;

static int
set_light_notifications(struct light_device_t* dev,
        struct light_state_t const* state)

    pthread_mutex_lock(&g_lock);
    g_notification = *state;
    handle_speaker_battery_locked(dev);
    pthread_mutex_unlock(&g_lock);
    return 0;


/** Open a new instance of a lights device using name */
static int open_lights(const struct hw_module_t* module, char const* name,
        struct hw_device_t** device)

    int (*set_light)(struct light_device_t* dev,
            struct light_state_t const* state);
    if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) 
        g_has_persistence_node = !access(PERSISTENCE_FILE, F_OK);
        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 if (0 == strcmp(LIGHT_ID_BUTTONS, name)) 
        if (!access(BUTTON_FILE, F_OK)) 
          // enable light button when the file is present
          set_light = set_light_buttons;
         else 
          return -EINVAL;
        
    

... ...

根据不同灯的类型执行不同函数,以通知灯电量灯为例,最后执 handle_speaker_battery_locked

static void
handle_speaker_battery_locked(struct light_device_t* dev)

    if (is_lit(&g_battery)) 
        set_speaker_light_locked(dev, &g_battery);
     else 
        set_speaker_light_locked(dev, &g_notification);
    

系统在这里对电量灯和通知灯做了区分,有电量指示灯时通知灯的设置是无效的。

以上是关于Android 通知灯设置的主要内容,如果未能解决你的问题,请参考以下文章

8.4 Android灯光系统_源码分析_电池灯

Android通知——Notification

Android通知——Notification

无法为奥利奥通知启用闪烁灯并禁用通知声音

使用工作灯的统一推送通知导致无法在 Android 上工作 (6.0.0.2)

为各种 Android 操作系统版本设置推送通知图标