目錄
- Notification介紹
- Notification框架原理
- Notification框架服務(wù)端啟動(dòng)過程
- SystemUI進(jìn)程啟動(dòng)和綁定NotificationManagerService服務(wù)端過程
- Notification調(diào)用過程
- Notification通知提示音響起過程
- 總結(jié)
Notification介紹
功能作用
- 顯示接收到短息、即時(shí)消息等信息 (如QQ、微信、新浪、短信)
- 顯示客戶端的推送消息(如有新版本發(fā)布,廣告,推薦新聞等)
- 顯示正在進(jìn)行的事務(wù)(例如:后臺(tái)運(yùn)行的程序)(如音樂播放器、版本更新時(shí)候的下載進(jìn)度等)
通知的基本組成

1. 標(biāo)題
2. 大圖標(biāo)
3. 內(nèi)容文字
4. 內(nèi)容信息
5. 小圖標(biāo)
6. 通知的時(shí)間(Timestamp,默認(rèn)為系統(tǒng)發(fā)出通知的時(shí)間,也可通過setWhen()來設(shè)置)
Notification框架原理
通知欄框架(Notificaiton),它適用于Android系統(tǒng)中交互事件的通知。它主要由三部分組成:系統(tǒng)服務(wù)端NotificationManagerService,通知顯示端SystemUI,還有創(chuàng)建和更新通知的App端。
NotificationManagerService作為框架的服務(wù)端,在系統(tǒng)啟動(dòng)時(shí)就會(huì)啟動(dòng)并在后臺(tái)運(yùn)行,顯示端SystemUI作為系統(tǒng)UI進(jìn)程,也是Notification框架的客戶端,在系統(tǒng)啟動(dòng)時(shí)也會(huì)啟動(dòng)并一直運(yùn)行。
其它模塊需調(diào)用Notification時(shí),只需要調(diào)用NotificationManager.notify(int,Notification)就可以發(fā)出通知。

根據(jù)Notification框架的原理,我們就分別按以下幾點(diǎn)來分析:
1. Notification框架服務(wù)端啟動(dòng)過程
2. SystemUI進(jìn)程啟動(dòng)和綁定NotificationManagerService服務(wù)端過程
3. Notification調(diào)用過程
4. Notification通知提示音響起過程
Notification框架相關(guān)的包
android/frameworks/base/services/java/com/android/server/SystemServer.java //系統(tǒng)服務(wù)類啟動(dòng)的地方
android/frameworks/base/core/java/com/android/server/LocalServices.java //系統(tǒng)服務(wù)類通信的輔助類
android/frameworks/base/core/java/android/service/notification/ //Notification服務(wù)的接口類和監(jiān)聽類
android/frameworks/base/services/core/java/com/android/server/notification/ //NotificationManagerService服務(wù)相關(guān)的類
android/frameworks/base/core/java/android/app/ //NotificationManager、Notification類和INotificationManager.aidl的包
android/frameworks/base/packages/SystemUI/ //Notification顯示的UI進(jìn)程
Notification框架的關(guān)系類圖

Notification框架服務(wù)端啟動(dòng)過程
SystemServer啟動(dòng)的Notification管理服務(wù)類是NotificationManagerService,保存到SystemServiceManager的是NotificationManagerService服務(wù)對(duì)象中的INotificationManager.Stub(),但是綁定到ServiceManager中Context.NOTIFICATION_ SERVICE的服務(wù)類是NotificationManager,所有開發(fā)者通過Context.getSystemService(Context.NOTIFICATION_SERVICE)獲取回來的服務(wù)類不是NotificationManagerServiced服務(wù)對(duì)象,而是NotificationManager對(duì)象,需要再通過NotificationManager對(duì)象中的getService()方法,獲取SystemServiceManager系統(tǒng)服務(wù)管理對(duì)象中保存的INotificationManager.Stub()對(duì)象。這樣NotificationManager就能通過INotificationManager.Stub()對(duì)象和NotificationManagerService服務(wù)對(duì)象進(jìn)行遠(yuǎn)程通信了
系統(tǒng)啟動(dòng)時(shí),SystemServiceRegistry類中會(huì)把NotificationManager注冊(cè)為系統(tǒng)服務(wù)提供給其它服務(wù)或者應(yīng)用獲取系統(tǒng)服務(wù)使用,
/android/frameworks/base/core/java/android/app/SystemServiceRegistry.java
private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
new HashMap<Class<?>, String>();
private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
new HashMap<String, ServiceFetcher<?>>();
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(String serviceName, Class<T> serviceClass,
ServiceFetcher<T> serviceFetcher) {
SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); //把注冊(cè)的服務(wù)保存到列表對(duì)象中
}
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
在Activity或者Service中,可以直接通過Context.getSystemService(Context.NOTIFICATION_SERVICE)就可以獲取系統(tǒng)服務(wù)使用。ActivityThread.performLaunchActivity()方法中創(chuàng)建ContextImpl對(duì)象并通過activity.attach()傳遞給Activity對(duì)象,再通過attachBaseContext()方法賦值給父類ContextWrapper中Context mBase對(duì)象,在Activity或者Service中調(diào)用getSystemService()方法,最終是調(diào)用ContextImpl中的getSystemService()方法。
//android/frameworks/base/core/java/android/app/ContextImpl.java
@Override
public Object getSystemService(String name) { //從注冊(cè)到系統(tǒng)的服務(wù)列表中獲取對(duì)應(yīng)的服務(wù)
//...
Object registrySystemService = SystemServiceRegistry.getSystemService(this, name);
return registrySystemService;
}
SystemServiceRegistry中注冊(cè)的NotificationManager對(duì)象,其實(shí)不是真正的Notification服務(wù),它只是一個(gè)調(diào)用接口對(duì)象,需要通過遠(yuǎn)程調(diào)用來實(shí)現(xiàn)和NotificationManagerService服務(wù)對(duì)象進(jìn)行通信,真正實(shí)現(xiàn)相應(yīng)的操作。以下是NotificationManagerService服務(wù)的啟動(dòng)流程。系統(tǒng)啟動(dòng)時(shí)會(huì)調(diào)用SystemServer來啟動(dòng)相應(yīng)的系統(tǒng)服務(wù)對(duì)象。
/android/frameworks/base/services/java/com/android/server/SystemServer.java
private SystemServiceManager mSystemServiceManager; //系統(tǒng)服務(wù)管理類
private void run() {
//...
//創(chuàng)建系統(tǒng)服務(wù)管理對(duì)象
mSystemServiceManager = new SystemServiceManager(mSystemContext);
//把系統(tǒng)服務(wù)管理對(duì)象保存到本地服務(wù)列表對(duì)象中,這樣在系統(tǒng)進(jìn)程中就可以通過LocalServices.getService(Class<T> type)
//直接返回本地服務(wù)列表中的服務(wù)對(duì)象進(jìn)行使用
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
//...
}
private void startOtherServices() {
//...
INotificationManager notification = null;
//...
mSystemServiceManager.startService(NotificationManagerService.class); //啟動(dòng)NotificationManagerService服務(wù)對(duì)象
//獲取NotificationManagerService服務(wù)對(duì)象的樁,用于進(jìn)行遠(yuǎn)程調(diào)用
notification = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
//...
}
/android/frameworks/base/services/core/java/com/android/server/SystemServiceManager.java //系統(tǒng)服務(wù)管理類
public <T extends SystemService> T startService(Class<T> serviceClass) {
final String name = serviceClass.getName();
final T service;
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
service = constructor.newInstance(mContext); //實(shí)例化服務(wù)
// Register it.
mServices.add(service); //注冊(cè)服務(wù)
// Start it.
service.onStart(); //啟動(dòng)服務(wù)
return service;
}
//系統(tǒng)服務(wù)類,NotificationManagerService的父類
/android/frameworks/base/services/core/java/com/android/server/SystemService.java
public abstract void onStart(); //抽象方法,在子類中實(shí)現(xiàn)
protected final void publishBinderService(String name, IBinder service) {
publishBinderService(name, service, false);
}
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated) {
ServiceManager.addService(name, service, allowIsolated);
}
//綁定和發(fā)布key為Context.NOTIFICATION_SERVICE的NotificationManager系統(tǒng)服務(wù)類
protected final <T> void publishLocalService(Class<T> type, T service) {
LocalServices.addService(type, service);
}
//添加到內(nèi)部系統(tǒng)服務(wù)類的集合類LocalServices中
private SystemServiceManager getManager() {
return LocalServices.getService(SystemServiceManager.class);
}
SystemServer中調(diào)用NotificationManagerService的onStart()方法來啟動(dòng)NotificationManagerService服務(wù)。
/android/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
public class NotificationManagerService extends SystemService {
@Override
public void onStart() {
mListeners = new NotificationListeners();
//綁定和發(fā)布key為Context.NOTIFICATION_SERVICE的NotificationManager系統(tǒng)服務(wù)類
publishBinderService(Context.NOTIFICATION_SERVICE, mService);
//添加到內(nèi)部系統(tǒng)服務(wù)類的集合類LocalServices中
publishLocalService(NotificationManagerInternal.class, mInternalService);
}
//只開放給系統(tǒng)內(nèi)部調(diào)用的API
private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
@Override
public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int[] idReceived, int userId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
idReceived, userId);
}
@Override
public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
int userId) {
checkCallerIsSystem();
synchronized (mNotificationList) {
int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
if (i < 0) {
return;
}
NotificationRecord r = mNotificationList.get(i);
StatusBarNotification sbn = r.sbn;
sbn.getNotification().flags =
(r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
mRankingHelper.sort(mNotificationList);
mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
}
}
};
//INotificationManager.Stub用于與NotificationManager類和SystemUI進(jìn)程進(jìn)行遠(yuǎn)程通信的樁 (或者其它模塊)
private final IBinder mService = new INotificationManager.Stub() {
@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); //添加或更新Notification
}
@Override
public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
checkCallerIsSystemOrSameApp(pkg);
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Binder.getCallingUid() == Process.SYSTEM_UID
? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL,
null); //刪除Notification
}
@Override
public void cancelAllNotifications(String pkg, int userId) {
checkCallerIsSystemOrSameApp(pkg);
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
REASON_NOMAN_CANCEL_ALL, null); //刪除所有Notification
}
@Override
public void registerListener(final INotificationListener listener,
final ComponentName component, final int userid) {
enforceSystemOrSystemUI("INotificationManager.registerListener");
//把NotificationListenerService對(duì)象注冊(cè)到ManagedServices服務(wù)管理子類NotificationListeners對(duì)象中
mListeners.registerService(listener, component, userid);
}
@Override
public void unregisterListener(INotificationListener listener, int userid) {
//把NotificationListenerService對(duì)象從ManagedServices服務(wù)管理子類NotificationListeners對(duì)象中解除
mListeners.unregisterService(listener, userid);
}
};
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int[] idOut, int incomingUserId) {
//...
mHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mNotificationList) {
//...
//調(diào)用服務(wù)管理對(duì)象mListeners來更新所有注冊(cè)到mListeners中的NotificationListenerService對(duì)象
mListeners.notifyPostedLocked(n, oldSbn);
//實(shí)現(xiàn)播放notification的鈴聲,使led燈亮起來或者震動(dòng)等操作。buzz:嗡嗡叫,beep: 嘟嘟響,blink: 閃爍
buzzBeepBlinkLocked(r);
}
}
});
idOut[0] = id;
}
//ManagedServices服務(wù)管理類,就是用于一類服務(wù)的管理對(duì)象,例如:如需要管理幾個(gè)同一類的服務(wù)對(duì)象NotificationListenerService
//只需要把相關(guān)的NotificationListenerService對(duì)象注冊(cè)到ManagedServices服務(wù)管理對(duì)象中,需要更新的時(shí)候,只需要調(diào)用
//ManagedServices服務(wù)管理對(duì)象對(duì)注冊(cè)的NotificationListenerService對(duì)象進(jìn)行更新即可
public class NotificationListeners extends ManagedServices {
public NotificationListeners() {
super(getContext(), mHandler, mNotificationList, mUserProfiles);
}
@Override
protected IInterface asInterface(IBinder binder) {
return INotificationListener.Stub.asInterface(binder);
}
//新添加的方法,調(diào)用這個(gè)方法,就會(huì)更新所有注冊(cè)進(jìn)來的NotificationListenerService對(duì)象來更新
//調(diào)用服務(wù)管理對(duì)象mListeners來更新所有注冊(cè)到mListeners中的NotificationListenerService對(duì)象
public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
StatusBarNotification sbnClone = null;
StatusBarNotification sbnCloneLight = null;
for (final ManagedServiceInfo info : mServices) {
//...
if (trim == TRIM_LIGHT && sbnCloneLight == null) {
sbnCloneLight = sbn.cloneLight();
} else if (trim == TRIM_FULL) {
sbnClone = sbn.clone();
}
final StatusBarNotification sbnToPost =
(trim == TRIM_FULL) ? sbnClone : sbnCloneLight;
mHandler.post(new Runnable() {
@Override
public void run() {
notifyPosted(info, sbnToPost, update); //調(diào)用更新通知方法
}
});
}
}
public void notifyRemovedLocked(StatusBarNotification sbn) {
final StatusBarNotification sbnLight = sbn.cloneLight();
for (final ManagedServiceInfo info : mServices) {
final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
mHandler.post(new Runnable() {
@Override
public void run() {
notifyRemoved(info, sbnLight, update);
}
});
}
}
//調(diào)用更新通知方法
private void notifyPosted(final ManagedServiceInfo info,
final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
final INotificationListener listener = (INotificationListener)info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
//回調(diào)NotificationListenerService對(duì)象中的方法onNotificationPosted(),在SystemUI中顯示Notification
listener.onNotificationPosted(sbnHolder, rankingUpdate);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
}
}
private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
NotificationRankingUpdate rankingUpdate) {
if (!info.enabledAndUserMatches(sbn.getUserId())) {
return;
}
final INotificationListener listener = (INotificationListener) info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
listener.onNotificationRemoved(sbnHolder, rankingUpdate);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
}
}
//...
}
}
//系統(tǒng)服務(wù)類,NotificationManagerService的父類
/android/frameworks/base/services/core/java/com/android/server/notification/ManagedServices.java
abstract protected IInterface asInterface(IBinder binder);
protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
abstract public class ManagedServices {
abstract protected void onServiceAdded(ManagedServiceInfo info);
protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
//把Service對(duì)象從ManagedServices服務(wù)管理類對(duì)象中刪除
public void unregisterService(IInterface service, int userid) {
checkNotNull(service);
unregisterServiceImpl(service, userid);
}
//把Service對(duì)象注冊(cè)到ManagedServices服務(wù)管理類對(duì)象中
public void registerService(IInterface service, ComponentName component, int userid) {
checkNotNull(service);
ManagedServiceInfo info = registerServiceImpl(service, component, userid);
if (info != null) {
onServiceAdded(info);
}
}
private ManagedServiceInfo registerServiceImpl(final IInterface service,
final ComponentName component, final int userid) {
synchronized (mMutex) {
try {
ManagedServiceInfo info = newServiceInfo(service, component, userid,
true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
service.asBinder().linkToDeath(info, 0);
mServices.add(info);
return info;
} catch (RemoteException e) {
}
}
return null;
}
private void unregisterServiceImpl(IInterface service, int userid) {
ManagedServiceInfo info = removeServiceImpl(service, userid);
if (info != null && info.connection != null) {
mContext.unbindService(info.connection);
}
}
}
SystemUI進(jìn)程啟動(dòng)和綁定NotificationManagerService服務(wù)端過程:
至此,Notification框架的服務(wù)端就已經(jīng)啟動(dòng)完畢,NotificationManagerService類只是管理Notification的邏輯,顯示端是在SystemUI進(jìn)程中實(shí)現(xiàn)的,那么NotificationManagerService服務(wù)對(duì)象和SystemUI進(jìn)程間是怎么通信的呢??jī)蓚€(gè)不同進(jìn)程間通信,很多同學(xué)可能就會(huì)想到Android的遠(yuǎn)程過程調(diào)用(Remote Procedure Call,RPC)方式來實(shí)現(xiàn),這種猜測(cè)是合理的,而且這里也的確是這么實(shí)現(xiàn)的。與很多其他的基于RPC的解決方案一樣,Android使用一種接口定義語(yǔ)言(Interface Definition Language,IDL)來公開服務(wù)的接口。所以我們先來看下NotificationManagerService服務(wù)和SystemUI進(jìn)程通信的服務(wù)接口文件:
/android/frameworks/base/core/java/android/app/INotificationManager.aidl
interface INotificationManager
{
void cancelAllNotifications(String pkg, int userId);
void enqueueToast(String pkg, ITransientNotification callback, int duration);
void cancelToast(String pkg, ITransientNotification callback);
void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
in Notification notification, inout int[] idReceived, int userId); //發(fā)出通知的方法
void cancelNotificationWithTag(String pkg, String tag, int id, int userId); //取消通知的方法
void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled); //Settings中關(guān)閉應(yīng)用通知
boolean areNotificationsEnabledForPackage(String pkg, int uid); //判斷應(yīng)用是否可發(fā)通知
void setPackagePriority(String pkg, int uid, int priority);
int getPackagePriority(String pkg, int uid);
void setPackagePeekable(String pkg, int uid, boolean peekable);
boolean getPackagePeekable(String pkg, int uid);
void setPackageVisibilityOverride(String pkg, int uid, int visibility);
int getPackageVisibilityOverride(String pkg, int uid);
// TODO: Remove this when callers have been migrated to the equivalent
// INotificationListener method.
StatusBarNotification[] getActiveNotifications(String callingPkg);
StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
//注冊(cè)INotificationListener服務(wù)的方法
void registerListener(in INotificationListener listener, in ComponentName component, int userid);
//解除INotificationListener服務(wù)的方法
void unregisterListener(in INotificationListener listener, int userid);
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
void setNotificationsShownFromListener(in INotificationListener token, in String[] keys);
ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim);
void requestHintsFromListener(in INotificationListener token, int hints);
int getHintsFromListener(in INotificationListener token);
void requestInterruptionFilterFromListener(in INotificationListener token, int interruptionFilter);
int getInterruptionFilterFromListener(in INotificationListener token);
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
boolean matchesMessageFilter(in Bundle extras);
boolean isSystemConditionProviderEnabled(String path);
int getZenMode();
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config, String reason);
oneway void setZenMode(int mode, in Uri conditionId, String reason);
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
boolean isNotificationPolicyAccessGranted(String pkg);
NotificationManager.Policy getNotificationPolicy(String pkg);
void setNotificationPolicy(String pkg, in NotificationManager.Policy policy);
String[] getPackagesRequestingNotificationPolicyAccess();
boolean isNotificationPolicyAccessGrantedForPackage(String pkg);
void setNotificationPolicyAccessGranted(String pkg, boolean granted);
byte[] getBackupPayload(int user);
void applyRestore(in byte[] payload, int user);
ParceledListSlice getAppActiveNotifications(String callingPkg, int userId);
//***************************************************************//
// ++ @noti.sysui [START] NotificationManager APIs for SEC ONLY //
//***************************************************************//
boolean isNotificationInterruptable(String pkg, String opPkg, String tag, int id,
in Notification notification, in long time, int userId);
void cancelSummaryNotificationWithTag(String pkg, String tag, int id, int userId);
//***************************************************************///
// -- @noti.sysui [START] NotificationManager APIs for SEC ONLY //
//***************************************************************//
//WTL_EDM_START
void clearAllNotificationsAsUser(int userId);
//WTL_EDM_END
void enqueueEdgeNotification(String pkg, String opPkg, int id, in Bundle extras, int userId); //發(fā)側(cè)屏通知的方法
void removeEdgeNotification(String pkg, int id, in Bundle extras, int userId); //刪除側(cè)屏通知的方法
}
/android/frameworks/base/core/java/android/service/notification/INotificationListener.aidl
oneway interface INotificationListener
{
void onListenerConnected(in NotificationRankingUpdate update);
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
void onNotificationRemoved(in IStatusBarNotificationHolder notificationHolder,
in NotificationRankingUpdate update);
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
void onListenerHintsChanged(int hints);
void onInterruptionFilterChanged(int interruptionFilter);
void onEdgeNotificationPosted(String pkg, int id, in Bundle extra);
void onEdgeNotificationRemoved(String pkg, int id, in Bundle extra);
}
這個(gè)接口類的服務(wù)端就是NotificationManagerService服務(wù)對(duì)象中的INotificationManager.Stub對(duì)象mService
private final IBinder mService = new INotificationManager.Stub(){};
客戶端可以通過以下方式來獲取和服務(wù)端通信的樁對(duì)象:
IBinder b = ServiceManager.getService(Context.NOTIFICATION_SERVICE);
INotificationManager service = INotificationManager.Stub.asInterface(b);
SystemUI進(jìn)程在初始化過程中,會(huì)創(chuàng)建一個(gè)NotificationListenerService服務(wù)類,服務(wù)對(duì)象中創(chuàng)建一個(gè)INotificationListener對(duì)象并通過遠(yuǎn)程過程調(diào)用把這個(gè)INotificationListener對(duì)象注冊(cè)到NotificationManagerService服務(wù)對(duì)象的服務(wù)管理類子類NotificationListeners對(duì)象mListeners中
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
private final NotificationListenerService mNotificationListener =
new NotificationListenerService() {
//...
@Override
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
if (sbn != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
String key = sbn.getKey();
boolean isUpdate = mNotificationData.get(key) != null;
if (isUpdate) {
updateNotification(sbn, rankingMap); //更新Notification
} else {
addNotification(sbn, rankingMap, null /* oldEntry */); //添加Notification
}
}
});
}
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn,
final RankingMap rankingMap) {
if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
if (sbn != null) {
final String key = sbn.getKey();
mHandler.post(new Runnable() {
@Override
public void run() {
removeNotification(key, rankingMap); //刪除Notification
}
});
}
}
//...
};
public void start() {
//...
mNotificationListener.registerAsSystemService(mContext,
new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
UserHandle.USER_ALL); //把NotificationListenerService對(duì)象注冊(cè)為系統(tǒng)服務(wù)并通過和NotificationManagerService服務(wù)遠(yuǎn)程通信
//...
}
/android/frameworks/base/core/java/android/service/notification/NotificationListenerService.java
public void registerAsSystemService(Context context, ComponentName componentName,
int currentUser) throws RemoteException {
mSystemContext = context;
if (mWrapper == null) {
mWrapper = new INotificationListenerWrapper();
}
INotificationManager noMan = getNotificationInterface();
//通過遠(yuǎn)程過程把INotificationListener注冊(cè)到NotificationManagerService服務(wù)對(duì)象中,
//這樣NotificationManagerService對(duì)象就可以通過INotificationListener通信對(duì)象
//直接回調(diào)SystemUI進(jìn)程中的NotificationListenerService對(duì)象來操作顯示UI
noMan.registerListener(mWrapper, componentName, currentUser);
mCurrentUser = currentUser;
}
private final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
mNoMan = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE)); //這里就是上面客戶端可以獲取和服務(wù)端通信的樁對(duì)象的過程
}
return mNoMan;
}
public void onNotificationPosted(StatusBarNotification sbn) {
// optional //在SystemUI中BaseStatusBar的NotificationListenerService重寫了這個(gè)方法
}
private class INotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
NotificationRankingUpdate update) {
StatusBarNotification sbn;
try {
sbn = sbnHolder.get();
} catch (RemoteException e) {
return;
}
synchronized (mWrapper) {
applyUpdate(update);
try {
if (sbn != null) {
NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
} else {
NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
}
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationPosted", t);
}
}
}
@Override
public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,NotificationRankingUpdate update) {}
@Override
public void onListenerConnected(NotificationRankingUpdate update) {}
@Override
public void onNotificationRankingUpdate(NotificationRankingUpdate update) throws RemoteException {}
@Override
public void onListenerHintsChanged(int hints) throws RemoteException {}
@Override
public void onInterruptionFilterChanged(int interruptionFilter) throws RemoteException {}
@Override
public void onEdgeNotificationPosted(String pkg, int id, Bundle extra) {}
@Override
public void onEdgeNotificationRemoved(String pkg, int id, Bundle extra) {}
}
Notification調(diào)用過程
Notification調(diào)用過程可以從應(yīng)用開始,通過NotificationManager.notify()來發(fā)出通知,NotificationManager通過和NotificationManagerService服務(wù)對(duì)象通信,NotificationManagerService服務(wù)對(duì)象再利用通過NotificationListeners中監(jiān)聽的服務(wù)列表與SystemUI進(jìn)程啟動(dòng)的系統(tǒng)服務(wù)NotificationListenerService中的INotificationListener對(duì)象通信,就可以調(diào)用SystemUI進(jìn)程進(jìn)行顯示。
調(diào)用過程如下圖所示:

對(duì)應(yīng)的代碼,如以下所示:
應(yīng)用程序要發(fā)通知或取消通知,只需要獲取系統(tǒng)的通知管理服務(wù),調(diào)用notify或者cancel來操作通知即可。
NotificationManager nm = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE); //獲取通知管理服務(wù)
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.drawable.smallicon)
.setContentTitle("This is Title")
.setContentText("This is Content");
Notification n = b.build(); //創(chuàng)建Notification
nm.notify(ID, n); //發(fā)通知
NotificationManager是管理通知的服務(wù)類,它負(fù)責(zé)與NotificationManagerService服務(wù)對(duì)象通信,并通過調(diào)用NotificationManagerService服務(wù)對(duì)象添加、更新、刪除通知等等,所支持的功能可以參照遠(yuǎn)程通信服務(wù)接口INotificationManager.aidl中公開的方法。
/android/frameworks/base/core/java/android/app/NotificationManager.java
private static INotificationManager sService;
static public INotificationManager getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService("notification"); //獲取系統(tǒng)服務(wù)的樁對(duì)象
sService = INotificationManager.Stub.asInterface(b); //把樁對(duì)象轉(zhuǎn)化成遠(yuǎn)程通信對(duì)象
return sService;
}
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
public void notify(String tag, int id, Notification notification)
{
int[] idOut = new int[1];
INotificationManager service = getService();
String pkg = mContext.getPackageName();
//...
Notification stripped = notification.clone();
Builder.stripForDelivery(stripped);
try {
//調(diào)用遠(yuǎn)程服務(wù)對(duì)象的enqueueNotificationWithTag()方法來調(diào)用NotificationManagerService對(duì)象發(fā)出通知
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
stripped, idOut, UserHandle.myUserId());
} catch (RemoteException e) {
}
}
NotificationManagerService服務(wù)對(duì)象只是處理邏輯,顯示的邏輯是放在系統(tǒng)UI的進(jìn)程SystemUI中去的,所以NotificationManagerService服務(wù)對(duì)象處理完邏輯后,還需要遠(yuǎn)程調(diào)用SystemUI進(jìn)程去更新顯示。所以SystemUI進(jìn)程需要把INotificationListener服務(wù)對(duì)象注冊(cè)到NotificationManagerService服務(wù)對(duì)象中來,當(dāng)需要更新UI是,就可以通過INotificationListener服務(wù)對(duì)象回調(diào)SystemUI進(jìn)程中的方法來更新。
/android/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
@Override
public void onStart() {
mListeners = new NotificationListeners();
}
private final IBinder mService = new INotificationManager.Stub() {
@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); //添加或更新Notification
}
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int[] idOut, int incomingUserId) {
//...
mHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mNotificationList) {
//...
//調(diào)用服務(wù)管理對(duì)象mListeners來更新所有注冊(cè)到mListeners中的NotificationListenerService對(duì)象
mListeners.notifyPostedLocked(n, oldSbn);
//實(shí)現(xiàn)播放notification的鈴聲,使led燈亮起來或者震動(dòng)等操作。buzz:嗡嗡叫,beep: 嘟嘟響,blink: 閃爍
buzzBeepBlinkLocked(r);
}
}
});
idOut[0] = id;
}
public class NotificationListeners extends ManagedServices {
public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
for (final ManagedServiceInfo info : mServices) {
mHandler.post(new Runnable() {
@Override
public void run() {
notifyPosted(info, sbnToPost, update); //調(diào)用更新通知方法
}
});
}
}
private void notifyPosted(final ManagedServiceInfo info,
final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
final INotificationListener listener = (INotificationListener)info.service;
StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
try {
//回調(diào)NotificationListenerService對(duì)象中的方法onNotificationPosted(),在SystemUI中顯示Notification
listener.onNotificationPosted(sbnHolder, rankingUpdate);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
}
}
INotificationListener服務(wù)對(duì)象是從BaseStatusBar對(duì)象中啟動(dòng)的系統(tǒng)服務(wù)BNotificationListenerService注冊(cè)到NotificationManagerService對(duì)象中的,當(dāng)NotificationManagerService服務(wù)對(duì)象通過INotificationListener服務(wù)對(duì)象回調(diào)SystemUI進(jìn)程中的方法時(shí),就可以調(diào)用BaseStatusBar對(duì)象中的方法來更新UI顯示了。
/android/frameworks/base/core/java/android/service/notification/NotificationListenerService.java
private class INotificationListenerWrapper extends INotificationListener.Stub {
@Override
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
NotificationRankingUpdate update) {
StatusBarNotification sbn;
try {
sbn = sbnHolder.get();
} catch (RemoteException e) {
return;
}
synchronized (mWrapper) {
applyUpdate(update);
try {
if (sbn != null) {
NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
} else {
NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
}
} catch (Throwable t) {
Log.w(TAG, "Error running onNotificationPosted", t);
}
}
}
}
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
private final NotificationListenerService mNotificationListener =
new NotificationListenerService() {
@Override
public void onNotificationPosted(final StatusBarNotification sbn,
final RankingMap rankingMap) {
if (sbn != null) {
mHandler.post(new Runnable() {
@Override
public void run() {
String key = sbn.getKey();
boolean isUpdate = mNotificationData.get(key) != null;
if (isUpdate) {
updateNotification(sbn, rankingMap); //更新Notification,
} else {
addNotification(sbn, rankingMap, null /* oldEntry */); //添加Notification
}
}
});
}
}
};
PhoneStatusBar是BaseStatusBar的子類,實(shí)現(xiàn)了BaseStatusBar中的相關(guān)方法,addNotification()就是其中之一,這個(gè)方法是用來添加Notification和狀態(tài)欄通知圖標(biāo)的。
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
public void addNotification(StatusBarNotification notification, RankingMap ranking,
Entry oldEntry) {
//...
Entry shadeEntry = createNotificationViews(notification); //創(chuàng)建狀態(tài)欄通知圖標(biāo)和通知列表行布局
//...
//把創(chuàng)建的狀態(tài)欄通知圖標(biāo)和通知列表行布局分別添加到狀態(tài)欄通知欄和通知列表NotificatioStackScrollLayout中
addNotificationViews(shadeEntry, ranking);
setAreThereNotifications();
//...
}
protected NotificationData.Entry createNotificationViews(StatusBarNotification sbn) { //創(chuàng)建狀態(tài)欄通知圖標(biāo)和通知列表行布局
final StatusBarIconView iconView = createIcon(sbn); //創(chuàng)建狀態(tài)欄通知圖標(biāo)
if (iconView == null) {
return null;
}
NotificationData.Entry entry = new NotificationData.Entry(sbn, iconView);
if (!inflateViews(entry, mStackScroller)) { //創(chuàng)建展開通知布局列表中的通知一行的布局
handleNotificationError(sbn, "Couldn't expand RemoteViews for: " + sbn);
return null;
}
return entry;
}
protected StatusBarIconView createIcon(StatusBarNotification sbn) { //創(chuàng)建狀態(tài)欄通知圖標(biāo)
Notification n = sbn.getNotification();
final StatusBarIconView iconView = new StatusBarIconView(mContext,
sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId()), n); //創(chuàng)建狀態(tài)欄通知圖標(biāo)布局View
iconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
final Icon smallIcon = n.getSmallIcon();
if (smallIcon == null) {
handleNotificationError(sbn,
"No small icon in notification from " + sbn.getPackageName());
return null;
}
final StatusBarIcon ic = new StatusBarIcon(
sbn.getUser(),
sbn.getPackageName(),
smallIcon,
n.iconLevel,
n.number,
n.tickerText);
if (!iconView.set(ic)) { //把StatusBarIcon傳到狀態(tài)欄通知圖標(biāo)布局View中
handleNotificationError(sbn, "Couldn't create icon: " + ic);
return null;
}
return iconView;
}
protected boolean inflateViews(Entry entry, ViewGroup parent) { //創(chuàng)建展開通知布局列表中的通知一行的布局
final StatusBarNotification sbn = entry.notification;
RemoteViews contentView = sbn.getNotification().contentView; //通知布局的contentView布局
RemoteViews bigContentView = sbn.getNotification().bigContentView; //通知布局的bigContentView布局
RemoteViews headsUpContentView = sbn.getNotification().headsUpContentView;//通知布局的headsUpContentView布局
Notification publicNotification = sbn.getNotification().publicVersion;
ExpandableNotificationRow row; //創(chuàng)建通知布局列表中的一行的布局
if (entry.row != null) {
} else {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
parent, false);
row.setExpansionLogger(this, entry.notification.getKey());
row.setGroupManager(mGroupManager);
}
NotificationContentView contentContainer = row.getPrivateLayout();
NotificationContentView contentContainerPublic = row.getPublicLayout();
NotificationContentView expandedKnox = row.getKnoxLayout();
mNotificationClicker.register(row, sbn);
View contentViewLocal = null;
View bigContentViewLocal = null;
View headsUpContentViewLocal = null;
try {
contentViewLocal = contentView.apply(
sbn.getPackageContext(mContext),
contentContainer,
mOnClickHandler); //把contentView添加到通知布局列表中通知行容器中
if (bigContentView != null) {
bigContentViewLocal = bigContentView.apply(
sbn.getPackageContext(mContext),
contentContainer,
mOnClickHandler); //把bigContentView添加到通知布局列表中通知行容器中
}
if (headsUpContentView != null) {
headsUpContentViewLocal = headsUpContentView.apply(
sbn.getPackageContext(mContext),
contentContainer,
mOnClickHandler); //把headsUpContentView添加到通知布局列表中通知行容器中
}
} catch (RuntimeException e) {
return false;
}
View publicViewLocal = null;
if (publicNotification != null) {
try {
publicViewLocal = publicNotification.contentView.apply(
sbn.getPackageContext(mContext),
contentContainerPublic, mOnClickHandler);
} catch (RuntimeException e) {
publicViewLocal = null;
}
}
//...
return true;
}
//把創(chuàng)建的狀態(tài)欄通知圖標(biāo)和通知列表行布局分別添加到狀態(tài)欄通知欄和通知列表NotificatioStackScrollLayout中
protected void addNotificationViews(Entry entry, RankingMap ranking) {
if (entry == null) {
return;
}
mNotificationData.add(entry, ranking); //先把通知添加到NotificationData中去
updateNotifications();//根據(jù)更新后的NotificationData數(shù)據(jù)更新狀態(tài)欄通知圖標(biāo)和通知列表NotificationStackScrollLayout布局
}
@Override
protected void updateNotifications() {
mNotificationData.filterAndSort(); //過濾和排序通知的順序
updateNotificationShade(); //添加或者更新NotificationStackScrollLayout中的Notification
mIconController.updateNotificationIcons(mNotificationData); //添加或者更新狀態(tài)欄左上角通知欄圖標(biāo)
mNotificationPanel.updateCarrierAndClearLayout(); //更新通信類型和清除布局
}
private void updateNotificationShade() {
ArrayList<Entry> activeNotifications = mNotificationData.getActiveNotifications();
ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
//把所有需要顯示的Notification添加到toShow列表中
final int N = activeNotifications.size();
for (int i=0; i<N; i++) {
Entry ent = activeNotifications.get(i);
toShow.add(ent.row);
}
//通過判斷mStackScroller中各個(gè)child是否在toShow列表;不在的話,就添加toRemove列表中,待會(huì)一起刪除
ArrayList<View> toRemove = new ArrayList<>();
for (int i=0; i< mStackScroller.getChildCount(); i++) {
View child = mStackScroller.getChildAt(i);
if (!toShow.contains(child) && child instanceof ExpandableNotificationRow) {//child是否在toShow列表
toRemove.add(child);
}
}
//把toRemove列表中需要?jiǎng)h除的child,都刪除掉
for (View remove : toRemove) {
mStackScroller.removeView(remove);
}
//判斷toShow列表中,有哪些是新添加的通知(可以通過通知View是否有父容器來判斷),新的通知就添加到mStackScroller中
for (int i=0; i<toShow.size(); i++) {
View v = toShow.get(i);
if (v.getParent() == null) { //這里通過通知View是否有父容器來判斷這條通知是否是新的
mStackScroller.addView(v); //新通知就添加到mStackScroller中
}
}
//以上已經(jīng)把需要顯示或者刪除的通知都處理完了,但是還需要重新調(diào)整順序
//從mStackScroller中順序判斷每個(gè)child的順序是否與toShow列表中的順序一樣
//不一樣的,就把順序調(diào)整下
int j = 0;
for (int i = 0; i < mStackScroller.getChildCount(); i++) {
View child = mStackScroller.getChildAt(i);
ExpandableNotificationRow targetChild = toShow.get(j);
if (child != targetChild) { //順序不對(duì)
mStackScroller.changeViewPosition(targetChild, i); //調(diào)整順序
}
j++;
}
updateNotificationShadeForChildren(); //更新每個(gè)Group Notification中的child Notification
updateRowStates(); //更新Notification布局中的Item展開情況、dim情況和鎖屏狀態(tài)下的通知布局情況,很重要的一個(gè)方法
updateClearAll(); //更新清楚所有按鈕布局
updateEmptyShadeView(); //隱藏"No Notification"
updateQsExpansionEnabled(); //關(guān)閉QS功能
mShadeUpdates.check();
}
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
public void filterAndSort() {
mSortedAndFiltered.clear(); //清除mSortedAndFiltered列表
final int N = mEntries.size();
for (int i = 0; i < N; i++) {
Entry entry = mEntries.valueAt(i);
StatusBarNotification sbn = entry.notification;
if (shouldFilterOut(sbn)) { //判斷是否需要過濾掉
continue;
}
mSortedAndFiltered.add(entry); //添加到mSortedAndFiltered列表中
}
Collections.sort(mSortedAndFiltered, mRankingComparator); //重新排序mSortedAndFiltered中的選項(xiàng)
}
StatusBarIconController是狀態(tài)欄圖標(biāo)控制的類,用來控制狀態(tài)欄通知圖標(biāo)顯示和系統(tǒng)圖標(biāo)顯示等等。
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
private IconMerger mNotificationIcons; //狀態(tài)欄通知圖標(biāo)容器對(duì)象
public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar,
PhoneStatusBar phoneStatusBar) {
//...
mNotificationIcons = (IconMerger) statusBar.findViewById(R.id.notificationIcons); //獲取狀態(tài)欄圖標(biāo)的容器類
//...
}
public void updateNotificationIcons(NotificationData notificationData) {
int iconSize = mContext.getResources().getDimensionPixelSize(R.dimen.notification_icon_view_width); //圖標(biāo)寬度
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
iconSize + 2*mIconHPadding, mPhoneStatusBar.getStatusBarHeight()); //狀態(tài)欄圖標(biāo)的布局參數(shù)(寬度x高度)
ArrayList<NotificationData.Entry> activeNotifications =
notificationData.getActiveNotifications();
final int N = activeNotifications.size();
ArrayList<StatusBarIconView> toShow = new ArrayList<>(N);
//把所有需要顯示的Notification添加到toShow列表中
for (int i = 0; i < N; i++) {
NotificationData.Entry ent = activeNotifications.get(i);
//過濾環(huán)境通知,例如:插USB或者充電線時(shí)的通知,是不需要顯示狀態(tài)欄中的圖標(biāo)的
if (notificationData.isAmbient(ent.key)
&& !NotificationData.showNotificationEvenIfUnprovisioned(ent.notification)) {
continue;
}
if (!PhoneStatusBar.isTopLevelChild(ent)) { //過濾分組的組圖標(biāo)
continue;
}
if ((ent.notification.getNotification().secFlags
& Notification.SEC_FLAG_HIDE_NOTIFICATION_ICON) !=0) { //過濾掉設(shè)置了隱藏狀態(tài)欄圖標(biāo)的通知
continue;
}
if(!mPhoneStatusBar.shouldShowOnIndicator(ent.notification.getKey())) { //過濾設(shè)置了隱藏圖標(biāo)的包的通知
continue;
}
toShow.add(ent.icon);
}
//通過判斷mNotificationIcons中各個(gè)child是否在toShow列表;不在的話,就添加toRemove列表中,待會(huì)一起刪除
ArrayList<View> toRemove = new ArrayList<>();
for (int i=0; i<mNotificationIcons.getChildCount(); i++) {
View child = mNotificationIcons.getChildAt(i);
if (!toShow.contains(child)) { //child是否在toShow列表
toRemove.add(child);
}
}
//把toRemove列表中需要?jiǎng)h除的child,都刪除掉
final int toRemoveCount = toRemove.size();
for (int i = 0; i < toRemoveCount; i++) {
mNotificationIcons.removeView(toRemove.get(i));
}
//判斷toShow列表中,有哪些是新添加的通知(可以通過通知View是否有父容器來判斷),新的通知就添加到mNotificationIcons中
for (int i=0; i<toShow.size(); i++) {
View v = toShow.get(i);
if (v.getParent() == null) { //這里通過通知View是否有父容器來判斷這條通知是否是新的
mNotificationIcons.addView(v, i, params); //新通知就添加到mStackScroller中
}
}
//以上已經(jīng)把需要顯示或者刪除的通知都處理完了,但是還需要重新調(diào)整順序
//從mNotificationIcons中順序判斷每個(gè)child的順序是否與toShow列表中的順序一樣
//不一樣的,就把順序調(diào)整下
final int childCount = mNotificationIcons.getChildCount();
for (int i = 0; i < childCount; i++) {
View actual = mNotificationIcons.getChildAt(i);
StatusBarIconView expected = toShow.get(i);
if (actual == expected) { //順序正確的就不處理
continue;
}
mNotificationIcons.removeView(expected); //把順序錯(cuò)誤的View先刪除
mNotificationIcons.addView(expected, i); //再添加到正確的順序位置上
}
applyNotificationIconsTint(); //更新狀態(tài)欄圖標(biāo)的顏色
}
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/IconMerger.java
public class IconMerger extends LinearLayout{ //狀態(tài)欄通知圖標(biāo)容器類
}
把狀態(tài)欄通知圖標(biāo)和通知行布局都分別添加到相應(yīng)的容器類后,顯示部分的邏輯也就完成了。
Notification通知提示音響起過程
SystemUI的RingtonePlayer服務(wù)通過IAudioService.setRingtonePlayer(IRingtonePlayer)把IRingtonePlayer實(shí)現(xiàn)的回調(diào)接口對(duì)象注冊(cè)到AudioService服務(wù)中,第三方App調(diào)用NotificationManager.notify()時(shí),會(huì)調(diào)用NotificationManagerService中的enqueueNotificationInternal方法中的buzzBeepBlinkLocked()方法,這個(gè)方法會(huì)通過IAudioService.getRingtonePlayer()獲取AudioServoce中的IRingtonePlayer對(duì)象,并調(diào)用回調(diào)方法來調(diào)用SystenUI.RingtonePlayer.mCallback的playAsync()來實(shí)現(xiàn)播放notification鈴聲、震動(dòng)、閃爍燈功能。
調(diào)用過程如下圖所示:

對(duì)應(yīng)的代碼,如以下所示:
啟動(dòng)AudioService服務(wù)過程,
/android/frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices() {
AudioService audioService = null;
audioService = new AudioService(context);
ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
}
/android/frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public class AudioService extends IAudioService.Stub {
private volatile IRingtonePlayer mRingtonePlayer;
@Override
public void setRingtonePlayer(IRingtonePlayer player) {
mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
mRingtonePlayer = player;
}
@Override
public IRingtonePlayer getRingtonePlayer() {
return mRingtonePlayer;
}
}
啟動(dòng)SystemUI的RingtonePlayer服務(wù)過程,
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();
}
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
private final Class<?>[] SERVICES = new Class[] {
com.android.systemui.tuner.TunerService.class,
com.android.systemui.keyguard.KeyguardViewMediator.class,
com.android.systemui.recents.Recents.class,
com.android.systemui.volume.VolumeUI.class,
com.android.systemui.statusbar.SystemBars.class,
com.android.systemui.usb.StorageNotification.class,
com.android.systemui.power.PowerUI.class,
com.android.systemui.media.RingtonePlayer.class, //RingtinePlayer服務(wù)
com.android.systemui.keyboard.KeyboardUI.class,
};
public void startServicesIfNeeded() {
//...
final int N = SERVICES.length;
for (int i=0; i<N; i++) {
Class<?> cl = SERVICES[i];
mServices[i] = (SystemUI)cl.newInstance();
mServices[i].mContext = this;
mServices[i].mComponents = mComponents;
mServices[i].start(); //啟動(dòng)RingtinePlayer服務(wù)
if (mBootCompleted) {
mServices[i].onBootCompleted();
}
}
//...
}
RingtonePlayer是運(yùn)行在SystemUI進(jìn)程的服務(wù),RingtonePlayer服務(wù)會(huì)獲取AudioService服務(wù)對(duì)象,并把IRingtonePlayer對(duì)象傳給AudioService服務(wù)對(duì)象中去,其它模塊通過AudioService.getRingtonePlayer()來控制RingtonePlayer服務(wù)播放提示音的功能。
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
//相關(guān)的遠(yuǎn)程過程調(diào)用接口:
/android/frameworks/base/media/java/android/media/IRingtonePlayer.aidl
/android/frameworks/base/media/java/android/media/IAudioService.aidl
private IAudioService mAudioService;
private final NotificationPlayer mAsyncPlayer = new NotificationPlayer(TAG);
private final HashMap<IBinder, Client> mClients = new HashMap<IBinder, Client>();
@Override
public void start() {
mAsyncPlayer.setUsesWakeLock(mContext);
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE)); //獲取AudioService服務(wù)的遠(yuǎn)程對(duì)象
mAudioService.setRingtonePlayer(mCallback); //把IRingtonePlayer傳到AudioService服務(wù)對(duì)象中去
}
//每個(gè)Client代表一個(gè)播放的任務(wù)
private class Client implements IBinder.DeathRecipient {
private final IBinder mToken;
private final Ringtone mRingtone;
public Client(IBinder token, Uri uri, UserHandle user, AudioAttributes aa) {
mToken = token;
mRingtone = new Ringtone(getContextForUser(user), false); //創(chuàng)建一個(gè)Ringtone對(duì)象
mRingtone.setAudioAttributes(aa);
mRingtone.setUri(uri);
}
@Override
public void binderDied() {
if (LOGD) Log.d(TAG, "binderDied() token=" + mToken);
synchronized (mClients) {
mClients.remove(mToken);
}
mRingtone.stop();
}
}
private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
@Override
public void play(IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping)
throws RemoteException {
Client client;
synchronized (mClients) {
client = mClients.get(token);
if (client == null) {
final UserHandle user = Binder.getCallingUserHandle();
client = new Client(token, uri, user, aa);
token.linkToDeath(client, 0);
mClients.put(token, client);
}
}
client.mRingtone.setLooping(looping);
client.mRingtone.setVolume(volume);
client.mRingtone.play(); //同步播放提示音
}
@Override
public void stop(IBinder token) {
Client client;
synchronized (mClients) {
client = mClients.remove(token);
}
if (client != null) {
client.mToken.unlinkToDeath(client, 0);
client.mRingtone.stop();
}
}
@Override
public boolean isPlaying(IBinder token) {
Client client;
synchronized (mClients) {
client = mClients.get(token);
}
if (client != null) {
return client.mRingtone.isPlaying();
} else {
return false;
}
}
@Override
public void setPlaybackProperties(IBinder token, float volume, boolean looping) {
Client client;
synchronized (mClients) {
client = mClients.get(token);
}
if (client != null) {
client.mRingtone.setVolume(volume);
client.mRingtone.setLooping(looping);
}
}
@Override
public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Async playback only available from system UID.");
}
mAsyncPlayer.play(getContextForUser(user), uri, looping, aa); //把播放任務(wù)放到異步隊(duì)列中
}
@Override
public void stopAsync() {
if (LOGD) Log.d(TAG, "stopAsync()");
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException("Async playback only available from system UID.");
}
mAsyncPlayer.stop();
}
@Override
public String getTitle(Uri uri) {
final UserHandle user = Binder.getCallingUserHandle();
return Ringtone.getTitle(getContextForUser(user), uri,
false /*followSettingsUri*/, false /*allowRemote*/);
}
@Override
public IBinder setOnCompletionListener(INotificationPlayerOnCompletionListener l) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
throw new SecurityException(
"setOnCompletionListener only available from system UID.");
}
return mAsyncPlayer.setOnCompletionListener(l);
}
};
如果需要調(diào)用異步方式來播放提示音,就需要用到NotificationPlayer這個(gè)類,它會(huì)把播放任務(wù)保存到隊(duì)列中,通過線程一個(gè)一個(gè)為隊(duì)列中每個(gè)提示音播放任務(wù)創(chuàng)建一個(gè)播放線程并執(zhí)行。
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
private static final class Command { //一個(gè)異步任務(wù)對(duì)應(yīng)一個(gè)Command對(duì)象
int code;
Context context;
Uri uri;
boolean looping;
AudioAttributes attributes;
long requestTime;
}
private LinkedList<Command> mCmdQueue = new LinkedList(); //異步任務(wù)隊(duì)列對(duì)象
public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes) {
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = PLAY;
cmd.context = context;
cmd.uri = uri;
cmd.looping = looping;
cmd.attributes = attributes;
synchronized (mCmdQueue) {
enqueueLocked(cmd); //把異步任務(wù)加入隊(duì)列中
mState = PLAY;
}
}
private void enqueueLocked(Command cmd) {
mCmdQueue.add(cmd); //把異步任務(wù)加入隊(duì)列對(duì)象mCmdQueue中
if (mThread == null) { //如果執(zhí)行任務(wù)線程已經(jīng)停止,創(chuàng)建線程并開始執(zhí)行
acquireWakeLock();
mThread = new CmdThread(); //創(chuàng)建執(zhí)行任務(wù)的線程
mThread.start(); //啟動(dòng)線程
}
}
private final class CmdThread extends java.lang.Thread {
CmdThread() {
super("NotificationPlayer-" + mTag);
}
public void run() {
while (true) {
Command cmd = null;
synchronized (mCmdQueue) {
cmd = mCmdQueue.removeFirst(); //取出隊(duì)列中第一個(gè)任務(wù)
}
switch (cmd.code) { //任務(wù)類型
case PLAY: //播放提示音任務(wù)
startSound(cmd); //播放提示音
break;
case STOP: //停止提示音任務(wù)
if (mPlayer != null) {
long delay = SystemClock.uptimeMillis() - cmd.requestTime;
if (delay > 1000) { //如果異步時(shí)間超過1s,打印出來,方便調(diào)試
Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
}
mPlayer.stop();
mPlayer.release();
mPlayer = null;
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
mAudioManagerWithAudioFocus.abandonAudioFocus(null);
mAudioManagerWithAudioFocus = null;
}
}
if((mLooper != null)
&& (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
mLooper.quit();
}
} else {
Log.w(mTag, "STOP command without a player");
}
break;
}
synchronized (mCmdQueue) {
if (mCmdQueue.size() == 0) {
mThread = null;
releaseWakeLock();
return;
}
}
}
}
}
private void startSound(Command cmd) {
try {
synchronized(mCompletionHandlingLock) {
if((mLooper != null)
&& (mLooper.getThread().getState() != Thread.State.TERMINATED)) {
mLooper.quit();
}
//為每個(gè)播放任務(wù)創(chuàng)建一個(gè)播放提示音線程
mCompletionThread = new CreationAndCompletionThread(cmd);
synchronized(mCompletionThread) {
mCompletionThread.start(); //開始執(zhí)行線程
mCompletionThread.wait(); //等待線程執(zhí)行完
}
}
long delay = SystemClock.uptimeMillis() - cmd.requestTime;
if (delay > 1000) { //如果異步時(shí)間超過1s,打印出來,方便調(diào)試
Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
}
}
catch (Exception e) {
Log.w(mTag, "error loading sound for " + cmd.uri, e);
}
}
private final class CreationAndCompletionThread extends Thread {
public Command mCmd;
public CreationAndCompletionThread(Command cmd) {
super();
mCmd = cmd;
}
public void run() {
Looper.prepare();
mLooper = Looper.myLooper();
synchronized(this) {
AudioManager audioManager =
(AudioManager) mCmd.context.getSystemService(Context.AUDIO_SERVICE);
try {
MediaPlayer player = new MediaPlayer(); //創(chuàng)建一個(gè)MediaPlayer對(duì)象
player.setAudioAttributes(mCmd.attributes);
player.setDataSource(mCmd.context, mCmd.uri);
player.setLooping(mCmd.looping);
player.prepare();
if ((mCmd.uri != null) && (mCmd.uri.getEncodedPath() != null)
&& (mCmd.uri.getEncodedPath().length() > 0)) {
if (!audioManager.isMusicActiveRemotely()) {
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus == null) {
if (mDebug) Log.d(mTag, "requesting AudioFocus");
if (mCmd.looping) { //獲取長(zhǎng)時(shí)間音頻焦點(diǎn)
audioManager.requestAudioFocus(null,
AudioAttributes.toLegacyStreamType(mCmd.attributes),
AudioManager.AUDIOFOCUS_GAIN);
} else { //獲取臨時(shí)音頻焦點(diǎn)
audioManager.requestAudioFocus(null,
AudioAttributes.toLegacyStreamType(mCmd.attributes),
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
}
mAudioManagerWithAudioFocus = audioManager;
} else {
if (mDebug) Log.d(mTag, "AudioFocus was previously requested");
}
}
}
}
player.setOnCompletionListener(NotificationPlayer.this);
player.setOnErrorListener(NotificationPlayer.this);
player.start(); //開始播放提示音
if (mPlayer != null) {
mPlayer.release();
}
mPlayer = player;
}
catch (Exception e) {
Log.w(mTag, "error loading sound for " + mCmd.uri, e);
}
this.notify();
}
Looper.loop();
}
};
應(yīng)用或者服務(wù)通過NotificationManager調(diào)用notify()發(fā)出通過,NotificationManager通過和NotificationManagerService服務(wù)通信,調(diào)用發(fā)出通知,并調(diào)用buzzBeepBlinkLocked()方法來觸發(fā)通知提示音、震動(dòng)或者led閃爍。
/android/frameworks/base/core/java/android/app/NotificationManager.java
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
public void notify(String tag, int id, Notification notification)
{
INotificationManager service = getService();
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
stripped, idOut, UserHandle.myUserId());
}
/android/frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
private final IBinder mService = new INotificationManager.Stub() {
@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 Notification notification,
int[] idOut, int incomingUserId) {
mHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mNotificationList) {
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, callingUid, callingPid, score, notification, user);
NotificationRecord r = new NotificationRecord(n, score);
NotificationRecord old = mNotificationsByKey.get(n.getKey());
//調(diào)用服務(wù)管理對(duì)象mListeners來更新所有注冊(cè)到mListeners中的NotificationListenerService對(duì)象
mListeners.notifyPostedLocked(n, oldSbn);
//實(shí)現(xiàn)播放notification的提示音,使led燈亮起來或者震動(dòng)等操作。buzz:嗡嗡叫,beep: 嘟嘟響,blink: 閃爍
buzzBeepBlinkLocked(r);
}
}
});
}
//實(shí)現(xiàn)播放notification的提示音,使led燈亮起來或者震動(dòng)等操作。buzz:嗡嗡叫,beep: 嘟嘟響,blink: 閃爍
private void buzzBeepBlinkLocked(NotificationRecord record) {
boolean buzz = false; //震動(dòng)
boolean beep = false; //提示音
boolean blink = false; //閃爍
final Notification notification = record.sbn.getNotification();
// Should this notification make noise, vibe, or use the LED?
final boolean aboveThreshold = record.score >= SCORE_INTERRUPTION_THRESHOLD;
final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
// If we're not supposed to beep, vibrate, etc. then don't.
final String disableEffects = disableNotificationEffects(record);
if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects);
}
boolean smsRingtone = getContext().getResources().getBoolean(
com.android.internal.R.bool.config_sms_ringtone_incall);
if ((disableEffects == null || (smsRingtone && mInCall)) //通話期間來短信鈴聲
&& (!(record.isUpdate
&& (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
&& (record.getUserId() == UserHandle.USER_ALL ||
record.getUserId() == currentUser ||
mUserProfiles.isCurrentProfile(record.getUserId()))
&& canInterrupt
&& mSystemReady
&& mAudioManager != null) { //判斷是否需要提示音或者震動(dòng)
//這里會(huì)發(fā)出一個(gè)Notification的AccessibilityEvent,這樣在輔助服務(wù)中才能收到這個(gè)事件,
//微信搶紅包的功能就是通過這個(gè)輔助事件才得以實(shí)現(xiàn)的
sendAccessibilityEvent(notification, record.sbn.getPackageName());
//提示音相關(guān)
if(!isPrayModeNotiOn(mContext)) { //判斷是否是在祈禱模式下
//判斷Notification是否設(shè)置了使用默認(rèn)提示音或者Notification設(shè)置的提示音文件剛好是默認(rèn)提示音文件
final boolean useDefaultSound =
(notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
Settings.System.DEFAULT_NOTIFICATION_URI
.equals(notification.sound);
Uri soundUri = null;
boolean hasValidSound = false;
if (useDefaultSound) { //判斷是否使用默認(rèn)Notification提示音
soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; //獲取默認(rèn)提示音Uri
ContentResolver resolver = getContext().getContentResolver();
hasValidSound = Settings.System.getString(resolver,
Settings.System.NOTIFICATION_SOUND) != null; //默認(rèn)提示音文件是否有效
} else if (notification.sound != null) {
soundUri = notification.sound; //獲取Notification的提示音Uri
hasValidSound = (soundUri != null); //提示音文件是否有效
}
if (hasValidSound) { //判斷是否是有效提示音
boolean looping =
(notification.flags & Notification.FLAG_INSISTENT) != 0; //是否設(shè)置了循環(huán)
AudioAttributes audioAttributes;
if (notification.audioAttributes != null) {
audioAttributes = notification.audioAttributes;
} else {
audioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
}
mSoundNotificationKey = record.getKey();
//Notification提示音音量是否為0和音頻焦點(diǎn)是否可用
if ((mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
&& !mAudioManager.isAudioFocusExclusive()) {
final long identity = Binder.clearCallingIdentity();
try {
//-----這里或通過AudioService來獲取IRingtonePlayer對(duì)象,最終會(huì)調(diào)用SystemUI進(jìn)程中的RingtonePlayer來播放提示音
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
player.playAsync(soundUri, record.sbn.getUser(), looping,
audioAttributes); //異步方式播放提示音
beep = true;
mIsPlaying = true;
if (mMethodRingtonePlayer != null) { //翻轉(zhuǎn)停止播放提示音功能的相關(guān)邏輯
if (mOverTurnPlayer != null && mOverTurnPlayer.isEnable() && !mOverTurnPlayer.isRegister()) {
mOverTurnPlayer.register();
//... //翻轉(zhuǎn)停止播放提示音功能的相關(guān)邏輯,這里先不贅述
}
}
}
} catch (RemoteException e) {
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
//震動(dòng)相關(guān)
final boolean hasCustomVibrate = notification.vibrate != null; //Notification是否設(shè)置震動(dòng)
final boolean convertSoundToVibration =
!hasCustomVibrate
&& hasValidSound
&& (mAudioManager.getRingerMode()
== AudioManager.RINGER_MODE_VIBRATE); //震動(dòng)模式下,需要把通知提示音變成震動(dòng)
final boolean useDefaultVibrate =
(notification.defaults & Notification.DEFAULT_VIBRATE) != 0; //Notification是否設(shè)置了默認(rèn)震動(dòng)
final boolean useHaptic = doesItUseHaptic(notification.haptic); //Notification是否設(shè)置了觸屏反饋
if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate ||useHaptic)
&& !(mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT)) { //判斷是否需要震動(dòng)
mVibrateNotificationKey = record.getKey();
buzz = true;
doVibrate((useDefaultVibrate || convertSoundToVibration), useHaptic, notification); //執(zhí)行震動(dòng)
}
}
if(beep || buzz) {
AccessibilityManager accManager = AccessibilityManager.getInstance(getContext());
accManager.onFlashNotification(record.getNotification().category);
}
}
//led燈相關(guān)
boolean wasShowLights = mLights.remove(record.getKey());
if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) {
mLights.add(record.getKey());
updateLightsLocked(); //更新led燈閃爍
if (mUseAttentionLight) {
mAttentionLight.pulse();
}
blink = true;
} else if (wasShowLights) {
updateLightsLocked(); //更新led燈閃爍
}
if ((buzz || beep || blink) && !isPrayModeNotiOn(mContext)) {
EventLogTags.writeNotificationAlert(record.getKey(),
buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
mHandler.post(mBuzzBeepBlinked);
}
}
private void doVibrate(boolean useDefaultVibrate, boolean useHaptic, Notification n) {
if (useHaptic) {
mVibrator.vibrate(n.haptic, -1, null,
Vibrator.MagnitudeTypes.NotificationMagnitude); //執(zhí)行震動(dòng)
} else if (useDefaultVibrate) {
long identity = Binder.clearCallingIdentity();
try {
mVibrator.vibrate(HapticFeedbackConstants.VIBE_NOTIFICATION, -1, null,
Vibrator.MagnitudeTypes.NotificationMagnitude); //執(zhí)行震動(dòng)
} finally {
Binder.restoreCallingIdentity(identity);
}
} else {
long identity2 = Binder.clearCallingIdentity();
try {
mVibrator.vibrate(n.vibrate, ((n.flags & Notification.FLAG_INSISTENT) != 0) ? 0: -1, null,
Vibrator.MagnitudeTypes.NotificationMagnitude); //執(zhí)行震動(dòng)
} finally {
Binder.restoreCallingIdentity(identity2);
}
}
}
NotificationManagerService服務(wù)中就是通過AudioService服務(wù)獲取IRingtonePlayer對(duì)象來控制SystemUI進(jìn)程進(jìn)行播放提示音的,
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
player.playAsync(soundUri, record.sbn.getUser(), looping, audioAttributes);
SystemUI進(jìn)程播放提示音的流程如下:
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
private final NotificationPlayer mAsyncPlayer = new NotificationPlayer(TAG);
private IRingtonePlayer mCallback = new IRingtonePlayer.Stub() {
@Override
public void playAsync(Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
mAsyncPlayer.play(getContextForUser(user), uri, looping, aa); //異步播放提示音
}
}
/android/frameworks/base/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
public void play(Context context, Uri uri, boolean looping, AudioAttributes attributes) {
Command cmd = new Command();
cmd.requestTime = SystemClock.uptimeMillis();
cmd.code = PLAY;
cmd.context = context;
cmd.uri = uri;
cmd.looping = looping;
cmd.attributes = attributes;
synchronized (mCmdQueue) {
enqueueLocked(cmd); //把異步播放提示音放到播放任務(wù)隊(duì)列中
mState = PLAY;
}
}
private void enqueueLocked(Command cmd) {
mCmdQueue.add(cmd);
if (mThread == null) {
acquireWakeLock();
mThread = new CmdThread(); //創(chuàng)建處理隊(duì)列任務(wù)的線程
mThread.start(); //啟動(dòng)線程開始處理隊(duì)列中的任務(wù)
}
}
private final class CmdThread extends java.lang.Thread {
public void run() {
while (true) {
Command cmd = null;
synchronized (mCmdQueue) {
cmd = mCmdQueue.removeFirst(); //取隊(duì)列中第一條播放任務(wù)
}
switch (cmd.code) {
case PLAY:
startSound(cmd); //開始處理播放提示音任務(wù)
break;
}
}
}
private void startSound(Command cmd) {
synchronized(mCompletionHandlingLock) {
mCompletionThread = new CreationAndCompletionThread(cmd);
synchronized(mCompletionThread) {
mCompletionThread.start(); //執(zhí)行播放提示音線程
mCompletionThread.wait();
}
}
}
private final class CreationAndCompletionThread extends Thread {
public Command mCmd;
public CreationAndCompletionThread(Command cmd) {
super();
mCmd = cmd;
}
public void run() {
Looper.prepare();
mLooper = Looper.myLooper();
synchronized(this) {
try {
MediaPlayer player = new MediaPlayer();
player.setAudioAttributes(mCmd.attributes);
player.setDataSource(mCmd.context, mCmd.uri);
player.setLooping(mCmd.looping);
player.prepare();
player.start(); //播放提示音
if (mPlayer != null) {
mPlayer.release();
}
catch (Exception e) {
Log.w(mTag, "error loading sound for " + mCmd.uri, e);
}
this.notify();
}
Looper.loop();
}
};
總結(jié)
要理解Notification框架的原理,需要理清NotificationManager和NotificationManagerService之間是怎么通信的,NotificationManagerService和SystemUI之間是怎么通信的。INotificationManager.Stub不僅作為NotificationManagerService和NotificationManager的遠(yuǎn)程通信方式,也是NotificationManagerService和SystemUI的遠(yuǎn)程通信方式,不過SystemUI進(jìn)程會(huì)創(chuàng)建和啟動(dòng)一個(gè)系統(tǒng)服務(wù)NotificationListenerService,這個(gè)系統(tǒng)服務(wù)通過INotificationManager.Stub把INotificationListener.Stub對(duì)象遠(yuǎn)程傳給NotificationListenerService服務(wù)中,讓NotificationListenerService服務(wù)通過INotificationListener.Stub對(duì)象和系統(tǒng)服務(wù)NotificationListenerService通信,系統(tǒng)服務(wù)NotificationListenerService再調(diào)用SystemUI進(jìn)程來更新UI。
