分析平台Android4.4,
Android 系统架构中:一个manager类对应一个aidl接口,一个manager对应一个底层的服务,notification也是这个架构。
1.一个普通apk调用notification实现呼吸灯灯效,主要是通过在Notification里面设置效果参数传入NotificationManagernotify方法 ,通过aidl接口转换传入NotificationManagerService
需要设置如下代码:
1.1:获取NotificationManager:
NotificationManager mNotificationManager=(NotificationManager)this.getSystemService(NOTIFICATION_SERVICE);
1.2:定义一个Notification:
Notification mNotification=new Notification();
1.3:设置Notification的各种属性:
//设置通知在状态栏显示的图标
mNotification.icon=R.drawable.icon;
//当我们点击通知时显示的内容
mNotification.tickerText="Button1通知内容.....";
//通知时发出的默认声音
mNotification.defaults=Notification.DEFAULT_SOUND;
Android支持三色灯提醒,可以根据不同的场景选择点亮不同颜色的灯。需要注意的是,只有设置Notification的标志位为FLAG_SHOW_LIGHTS,才能支持三色灯提醒。创建三色灯提醒的Notification示例如下:
mNotification.flags |= Notification.FLAG_SHOW_LIGHTS;
提醒标志位(
Notification支持FLAG_SHOW_LIGHTS、FLAG_ONGOING_EVENT、FLAG_INSISTENT、FLAG_ ONLY_ALERT_ONCE、FLAG_AUTO_CANCEL、FLAG_NO_CLEAR、FLAG_FOREGROUND_SERVICE等多种提醒标志位,其含义分别如下:
FLAG_SHOW_LIGHTS //三色灯提醒
FLAG_ONGOING_EVENT //发起事件
FLAG_INSISTENT //振铃音将持续到Notification取消或Notification窗口打开
FLAG_ONLY_ALERT_ONCE //发起Notification后,振铃音或振动均只执行一次
FLAG_AUTO_CANCEL //用户单击后自动消失
FLAG_NO_CLEAR //只有全部清除时,Notification才会清除
FLAG_FOREGROUND_SERVICE //表示正运行的服务)
mNotification.ledARGB = 0xff0000f;//Led颜色
mNotification.ledOnMS = 300;//led亮的时间
mNotification.ledOffMS = 300;;//led灭的时间
//设置通知显示的参数
PendingIntent m_PendingIntent=PendingIntent.getActivity(NotificationDemo.this, 0, m_Intent, 0);
mNotification.setLatestEventInfo(NotificationDemo.this, "Button1", "Button1通知",m_PendingIntent );
//开始执行这个通知
mNotificationManager.notify(0,mNotification);
将设置好的参数信息打包到m_Notification中传入NotificationManager继续处理
2.在frameworks/base/core/java/android/app/NotificationManager.java中
static public INotificationManager getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService("notification");
sService = INotificationManager.Stub.asInterface(b);
return sService;
}
public void notify(String tag, int id, Notification notification)
{
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
if (notification.sound != null) {
notification.sound = notification.sound.getCanonicalUri();
if (StrictMode.vmFileUriExposureEnabled()) {
notification.sound.checkFileUriExposed("Notification.sound");
}
}
if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
Notification stripped = notification.clone();
Builder.stripForDelivery(stripped);
try {
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
stripped, idOut, UserHandle.myUserId());
if (id != idOut[0]) {
Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
}
} catch (RemoteException e) {
}
}
通过aidl接口调用到 NotificationManagerService中的enqueueNotificationWithTag方法中,enqueue说明notification的内部维护着一个队列,接收不同apk发送的通知请求。
3.在frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java中实现了灯效,亮灭时长灯的逻辑控制。
其中定义了MAX_PACKAGE_NOTIFICATIONS = 50,最大可以接收五十个通知
@Override
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Notification notification, int[] idOut, int userId) throws RemoteException {
enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Binder.getCallingPid(), tag, id,notification, idOut, userId);
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notificationnotification,
int[] idOut, int incomingUserId) {……….
…………………………..
………………….
}在这里对mNotificationList通知消息队列各条通知的优先级,声音进行了相关操作
最后进入updateLightsLocked在其中将设置好的灯效颜色,类型,时间长短写入LightsService
mNotificationLight.setFlashing(ledARGB, LightsService.LIGHT_FLASH_TIMED,
ledOnMS, ledOffMS);
4.在frameworks/base/services/core/java/com/android/server/lights/LightsService.java中setFlashing方法里面setLightLocked来实现等效。
所有对灯效的操作都是通过setLightLocked实现。如下
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 + ", " + 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;
}
setLight_native最终调用了一个native方法,到JNI层去了。
在frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp中还是将LED灯颜色,模式,时间写入state中向下继续传递
static void setLight_native(JNIEnv *env, jobject clazz, jlong ptr,
jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint 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;
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
devices->lights[light]->set_light(devices->lights[light], &state);
}
}
最后通过hardwareinterface控制led灯颜色节点实现灯效的具体效果!