1.简介
整理一下发送一个新的通知,源码层的逻辑
1.1.测试代码
就是通知管理器发送一个通知,学习下流程
notificationManager.notify(id, notification)
>1.notify
public void notify(int id, Notification notification)
{
notify(null, id, notification);
}
public void notify(String tag, int id, Notification notification)
{
notifyAsUser(tag, id, notification, mContext.getUser());
}
public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
{
INotificationManager service = getService();
String pkg = mContext.getPackageName();
try {//这里就走到2.1
service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
fixNotification(notification), user.getIdentifier());
}
}
2.INotificationManager
小节4NMS里的变量
final IBinder mService = new INotificationManager.Stub() {
2.1.enqueueNotificationWithTag
public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Notification notification, int userId) throws RemoteException {
//见4.1
enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Binder.getCallingPid(), tag, id, notification, userId);
}
2.2.requestBindListener
绑定通知监听服务
public void requestBindListener(ComponentName component) {
checkCallerIsSystemOrSameApp(component.getPackageName());
try {
ManagedServices manager =
mAssistants.isComponentEnabledForCurrentProfiles(component)
? mAssistants
: mListeners;
manager.setComponentState(component, UserHandle.getUserId(uid), true);
}
}
2.3.setNotificationListenerAccessGrantedForUser
public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
boolean granted, boolean userSet) {
//..
try {//权限检查,这里是空,所以为true
if (mAllowedManagedServicePackages.test(
listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
userId, false, granted, userSet);
//见11.8,加入approved集合
mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
userId, true, granted, userSet);
//发送广播
getContext().sendBroadcastAsUser(new Intent(
ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
.setPackage(listener.getPackageName())
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
UserHandle.of(userId), null);
//保存数据
handleSavePolicyFile();
}
}
}
3.NotificationManagerInternal
private final NotificationManagerInternal mInternalService = new NotificationManagerInternal()
3.1.getNotificationChannel
public NotificationChannel getNotificationChannel(String pkg, int uid, String
channelId) {
return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
}
3.2.enqueueNotification
- 服务里边调用startForeground发送一个前台通知,一路走下去到ServiceRecord.java,里边postNotification里会调用
public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, Notification notification, int userId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
userId);
}
3.3.cancelNotification
public void cancelNotification(String pkg, String opPkg, int callingUid, int callingPid,
String tag, int id, int userId) {
cancelNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, userId);
}
4.NotificationManagerService
4.1.enqueueNotificationInternal
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId) {
enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
incomingUserId, false);
}
void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int incomingUserId, boolean postSilently) {
//..
final int userId = ActivityManager.handleIncomingUser(callingPid,
callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
final UserHandle user = UserHandle.of(userId);
//
final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
if (notificationUid == INVALID_UID) {
throw new SecurityException("Caller " + opPkg + ":" + callingUid
+ " trying to post for invalid pkg " + pkg + " in user " + incomingUserId);
}
checkRestrictedCategories(notification);
// 补充1,调整通知
try {
fixNotification(notification, pkg, tag, id, userId);
} catch (Exception e) {
if (notification.isForegroundService()) {
throw new SecurityException("Invalid FGS notification", e);
}
return;
}
final ServiceNotificationPolicy policy = mAmi.applyForegroundServiceNotification(
notification, tag, id, pkg, userId);
if (policy == ServiceNotificationPolicy.UPDATE_ONLY) {
if (!isNotificationShownInternal(pkg, tag, id, userId)) {
reportForegroundServiceUpdate(false, notification, id, pkg, userId);
return;
}
}
mUsageStats.registerEnqueuedByApp(pkg);
//创建状态栏通知对象
final StatusBarNotification n = new StatusBarNotification(
pkg, opPkg, id, tag, notificationUid, callingPid, notification,
user, null, System.currentTimeMillis());
String channelId = notification.getChannelId();
String shortcutId = n.getShortcutId();
final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
pkg, notificationUid, channelId, shortcutId,
true /* parent ok */, false /* includeDeleted */);
//通知所属的channel为空
if (channel == null) {
boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);
if (!appNotificationsOff) {
//提示
doChannelWarningToast(notificationUid,
"Developer warning for package \"" + pkg + "\"\n" +
"Failed to post notification on channel \"" + channelId + "\"\n" +
"See log for more details");
}
return;
}
//创建通知记录对象
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId));
r.setPostSilently(postSilently);
r.setFlagBubbleRemoved(false);
r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
r.setImportanceFixed(isImportanceFixed);
//前台通知
if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
final boolean fgServiceShown = channel.isFgServiceShown();
if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
|| !fgServiceShown)
&& (r.getImportance() == IMPORTANCE_MIN
|| r.getImportance() == IMPORTANCE_NONE)) {
if (TextUtils.isEmpty(channelId)
|| NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
r.setSystemImportance(IMPORTANCE_LOW);
} else {
channel.setImportance(IMPORTANCE_LOW);
r.setSystemImportance(IMPORTANCE_LOW);
if (!fgServiceShown) {
channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
channel.setFgServiceShown(true);
}
mPreferencesHelper.updateNotificationChannel(
pkg, notificationUid, channel, false);
r.updateNotificationChannel(channel);
}
} else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
&& !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
channel.setFgServiceShown(true);
r.updateNotificationChannel(channel);
}
}
ShortcutInfo info = mShortcutHelper != null
? mShortcutHelper.getValidShortcutInfo(notification.getShortcutId(), pkg, user)
: null;
r.setShortcutInfo(info);
r.setHasSentValidMsg(mPreferencesHelper.hasSentValidMsg(pkg, notificationUid));
r.userDemotedAppFromConvoSpace(
mPreferencesHelper.hasUserDemotedInvalidMsgApp(pkg, notificationUid));
//检查通知是否可以post
if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
r.getSbn().getOverrideGroupKey() != null)) {
return;
}
if (info != null) {
mShortcutHelper.cacheShortcut(info, user);
}
if (notification.allPendingIntents != null) {
final int intentCount = notification.allPendingIntents.size();
if (intentCount > 0) {
final long duration = LocalServices.getService(
DeviceIdleInternal.class).getNotificationAllowlistDuration();
for (int i = 0; i < intentCount; i++) {
PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
if (pendingIntent != null) {
mAmi.setPendingIntentAllowlistDuration(pendingIntent.getTarget(),
ALLOWLIST_TOKEN, duration,
TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
REASON_NOTIFICATION_SERVICE,
"NotificationManagerService");
mAmi.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
ALLOWLIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
| FLAG_SERVICE_SENDER));
}
}
}
}
//需要升级特权来获得包的重要性
final long token = Binder.clearCallingIdentity();
boolean isAppForeground;
try {
isAppForeground = mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
} finally {
Binder.restoreCallingIdentity(token);
}
//见4.2
mHandler.post(new EnqueueNotificationRunnable(userId, r, isAppForeground,
SystemClock.elapsedRealtime()));
}
>1.fixNotification
通知进行适配调整
protected void fixNotification(Notification notification, String pkg, String tag, int id,
int userId) throws NameNotFoundException, RemoteException {
final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Notification.addFieldsFromContext(ai, notification);
//彩色通知权限
int canColorize = mPackageManagerClient.checkPermission(
android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
if (canColorize == PERMISSION_GRANTED) {
notification.flags |= Notification.FLAG_CAN_COLORIZE;
} else {
notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
}
if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
//全屏通知需要权限
int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
if (fullscreenIntentPermission != PERMISSION_GRANTED) {
notification.fullScreenIntent = null;//没有权限,数据置为空
}
}
// Ensure CallStyle has all the correct actions
if (notification.isStyle(Notification.CallStyle.class)) {
Notification.Builder builder =
Notification.Builder.recoverBuilder(getContext(), notification);
Notification.CallStyle style = (Notification.CallStyle) builder.getStyle();
List<Notification.Action> actions = style.getActionsListWithSystemActions();
notification.actions = new Notification.Action[actions.size()];
actions.toArray(notification.actions);
}
//确保MediaStyle对远程设备附加功能具有正确的权限
if (notification.isStyle(Notification.MediaStyle.class)) {
//多媒体类型的通知,需要权限
int hasMediaContentControlPermission = mPackageManager.checkPermission(
android.Manifest.permission.MEDIA_CONTENT_CONTROL, pkg, userId);
if (hasMediaContentControlPermission != PERMISSION_GRANTED) {
notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_DEVICE);
notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_ICON);
notification.extras.remove(Notification.EXTRA_MEDIA_REMOTE_INTENT);
}
}
//确保只有允许的包有一个替代的应用程序名称
if (notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) {
//权限检查
int hasSubstituteAppNamePermission = mPackageManager.checkPermission(
permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg, userId);
if (hasSubstituteAppNamePermission != PERMISSION_GRANTED) {
notification.extras.remove(Notification.EXTRA_SUBSTITUTE_APP_NAME);
}
}
//尺寸检查,太大的话设置为空
checkRemoteViews(pkg, tag, id, notification);
}
4.2.EnqueueNotificationRunnable
一个把通知数据插入队列的Runnable
public void run() {
synchronized (mNotificationLock) {
final Long snoozeAt =
mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
r.getUser().getIdentifier(),
r.getSbn().getPackageName(), r.getSbn().getKey());
final long currentTime = System.currentTimeMillis();
if (snoozeAt.longValue() > currentTime) {
(new SnoozeNotificationRunnable(r.getSbn().getKey(),
snoozeAt.longValue() - currentTime, null)).snoozeLocked(r);
return;
}
final String contextId =
mSnoozeHelper.getSnoozeContextForUnpostedNotification(
r.getUser().getIdentifier(),
r.getSbn().getPackageName(), r.getSbn().getKey());
if (contextId != null) {
(new SnoozeNotificationRunnable(r.getSbn().getKey(),
0, contextId)).snoozeLocked(r);
return;
}
//加入队列
mEnqueuedNotifications.add(r);
//见补充1,如果有设置自动取消通知时间的
scheduleTimeoutLocked(r);
final StatusBarNotification n = r.getSbn();
NotificationRecord old = mNotificationsByKey.get(n.getKey());
if (old != null) {
//保留以前记录中的排名信息
r.copyRankingInformation(old);
}
final int callingUid = n.getUid();
final int callingPid = n.getInitialPid();
final Notification notification = n.getNotification();
final String pkg = n.getPackageName();
final int id = n.getId();
final String tag = n.getTag();
updateNotificationBubbleFlags(r, isAppForeground);
handleGroupedNotificationLocked(r, old, callingUid, callingPid);
//群组通知里的一种,更新summary
if (n.isGroup() && notification.isGroupChild()) {
mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
}
//
if (!pkg.equals("com.android.providers.downloads")
|| Log.isLoggable("DownloadManager", Log.VERBOSE)) {
int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
if (old != null) {
enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
}
}
// tell the assistant service about the notification
if (mAssistants.isEnabled()) {
mAssistants.onNotificationEnqueuedLocked(r);
mHandler.postDelayed(
new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
r.getUid(), enqueueElapsedTimeMs),
DELAY_FOR_ASSISTANT_TIME);
} else {
//见4.3
mHandler.post(new PostNotificationRunnable(r.getKey(),
r.getSbn().getPackageName(), r.getUid(), enqueueElapsedTimeMs));
}
}
}
>1.scheduleTimeoutLocked
处理超时自动取消的广播,这里添加了一个闹铃,到时候取消通知
void scheduleTimeoutLocked(NotificationRecord record) {
//有设置超时时间的
if (record.getNotification().getTimeoutAfter() > 0) {
//封装一个意图广播,到时间发送广播
final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
REQUEST_CODE_TIMEOUT,
new Intent(ACTION_NOTIFICATION_TIMEOUT)//见补充2处理
.setPackage(PackageManagerService.PLATFORM_PACKAGE_NAME)
.setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
.appendPath(record.getKey()).build())
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
.putExtra(EXTRA_KEY, record.getKey()),
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
//通过闹铃管理器处理
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
}
}
>2.mNotificationTimeoutReceiver
private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
final NotificationRecord record;
synchronized (mNotificationLock) {
record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
}
if (record != null) {
//取消通知
cancelNotification(record.getSbn().getUid(), record.getSbn().getInitialPid(),
record.getSbn().getPackageName(), record.getSbn().getTag(),
record.getSbn().getId(), 0,
FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
REASON_TIMEOUT, null);
}
}
}
};
4.3.PostNotificationRunnable
处理通知发送的Runnable
public void run() {
//没有发送通知的权限,则为true
boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid);
//通话中
boolean isCallNotification = isCallNotification(pkg, uid);
synchronized (mNotificationLock) {
try {
NotificationRecord r = null;
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
if (Objects.equals(key, enqueued.getKey())) {
r = enqueued;
break;
}
}
if (r == null) {
return;
}
final StatusBarNotification n = r.getSbn();
final Notification notification = n.getNotification();
boolean isCallNotificationAndCorrectStyle = isCallNotification
&& notification.isStyle(Notification.CallStyle.class);
if (!(notification.isMediaNotification() || isCallNotificationAndCorrectStyle)
&& (appBanned || isRecordBlockedLocked(r))) {
mUsageStats.registerBlocked(r);
//通知被禁止的
return;
}
//包是挂起状态
final boolean isPackageSuspended =
isPackagePausedOrSuspended(r.getSbn().getPackageName(), r.getUid());
r.setHidden(isPackageSuspended);
if (isPackageSuspended) {
mUsageStats.registerSuspendedByAdmin(r);
}
//获取旧的通知记录
NotificationRecord old = mNotificationsByKey.get(key);
if (old == null || old.getSbn().getInstanceId() == null) {
n.setInstanceId(mNotificationInstanceIdSequence.newInstanceId());
} else {
n.setInstanceId(old.getSbn().getInstanceId());
}
//获取在通知列表里的索引
int index = indexOfNotificationLocked(n.getKey());
if (index < 0) {//没找到,新加通知
mNotificationList.add(r);
mUsageStats.registerPostedByApp(r);
mUsageStatsManagerInternal.reportNotificationPosted(r.getSbn().getOpPkg(),
r.getSbn().getUser(), postElapsedTimeMs);
final boolean isInterruptive = isVisuallyInterruptive(null, r);
r.setInterruptive(isInterruptive);
r.setTextChanged(isInterruptive);
} else {//有旧的,更新通知
old = mNotificationList.get(index); // Potentially *changes* old
mNotificationList.set(index, r);
mUsageStats.registerUpdatedByApp(r, old);
mUsageStatsManagerInternal.reportNotificationUpdated(r.getSbn().getOpPkg(),
r.getSbn().getUser(), postElapsedTimeMs);
// Make sure we don't lose the foreground service state.
notification.flags |=
old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
r.isUpdate = true;
final boolean isInterruptive = isVisuallyInterruptive(old, r);
r.setTextChanged(isInterruptive);
}
mNotificationsByKey.put(n.getKey(), r);
//前台服务通知,添加必要的flag
if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
notification.flags |= FLAG_NO_CLEAR;
if (!mAllowFgsDismissal) {
notification.flags |= FLAG_ONGOING_EVENT;
}
}
//排序
mRankingHelper.extractSignals(r);
mRankingHelper.sort(mNotificationList);
final int position = mRankingHelper.indexOf(mNotificationList, r);
int buzzBeepBlinkLoggingCode = 0;
if (!r.isHidden()) {
//见补充1,获取声音震动闪灯的状态,封装成一个值返回
buzzBeepBlinkLoggingCode = buzzBeepBlinkLocked(r);
}
if (notification.getSmallIcon() != null) {
StatusBarNotification oldSbn = (old != null) ? old.getSbn() : null;
//更新状态栏通知
mListeners.notifyPostedLocked(r, old);
//旧的通知为空或者新旧通知的group不一样。并且新的非紧急通知
if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
&& !isCritical(r)) {//补充2
mHandler.post(() -> {
synchronized (mNotificationLock) {
//发布新的状态栏通知
mGroupHelper.onNotificationPosted(
n, hasAutoGroupSummaryLocked(n));
}
});
} else if (oldSbn != null) {
final NotificationRecord finalRecord = r;
//更新状态栏通知
mHandler.post(() ->
mGroupHelper.onNotificationUpdated(finalRecord.getSbn()));
}
} else {
//通知没有设置smallIcon,这是有问题的
if (old != null && !old.isCanceled) {
//移除旧的通知
mListeners.notifyRemovedLocked(r,
NotificationListenerService.REASON_ERROR, r.getStats());
mHandler.post(new Runnable() {
@Override
public void run() {
mGroupHelper.onNotificationRemoved(n);
}
});
}
}
if (mShortcutHelper != null) {
mShortcutHelper.maybeListenForShortcutChangesForBubbles(r,
false /* isRemoved */,
mHandler);
}
maybeRecordInterruptionLocked(r);
maybeRegisterMessageSent(r);
maybeReportForegroundServiceUpdate(r, true);
} finally {
//末尾从队列集合里移除当前已处理的通知
int N = mEnqueuedNotifications.size();
for (int i = 0; i < N; i++) {
final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
if (Objects.equals(key, enqueued.getKey())) {
mEnqueuedNotifications.remove(i);
break;
}
}
}
}
}
>1.buzzBeepBlinkLocked
确定通知是否应该发出声音,震动,闪烁
int buzzBeepBlinkLocked(NotificationRecord record) {
if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
//汽车并且通知效果不可用
return 0;
}
boolean buzz = false;
boolean beep = false;
boolean blink = false;
final String key = record.getKey();
//重要性大于等于默认值3的才有效果的
final boolean aboveThreshold =
mIsAutomotive
? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
: record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
//请记住此通知是否已经拥有通知通道
boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
//如果允许通知发出噪声,则在条件中设置这些参数
boolean hasValidVibrate = false;
boolean hasValidSound = false;
boolean sentAccessibilityEvent = false;
// 如果通知将出现在状态栏中,它应该发送一个可访问性事件
final boolean suppressedByDnd = record.isIntercepted()
&& (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
if (!record.isUpdate
&& record.getImportance() > IMPORTANCE_MIN
&& !suppressedByDnd
&& isNotificationForCurrentUser(record)) {
sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
if (aboveThreshold && isNotificationForCurrentUser(record)) {
if (mSystemReady && mAudioManager != null) {
Uri soundUri = record.getSound();
hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
VibrationEffect vibration = record.getVibration();
//如果缺少振动且手机处于振动模式,则将声音调为振动
if (vibration == null
&& hasValidSound
&& (mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_VIBRATE)
&& mAudioManager.getStreamVolume(
AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
boolean insistent = (record.getFlags() & Notification.FLAG_INSISTENT) != 0;
vibration = mVibratorHelper.createFallbackVibration(insistent);
}
hasValidVibrate = vibration != null;
boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
//见补充3
if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
if (!sentAccessibilityEvent) {
sendAccessibilityEvent(record);
sentAccessibilityEvent = true;
}
//持续更新,就是连续的通知。。
boolean isInsistentUpdate = isInsistentUpdate(record);
if (hasValidSound) {
if (isInsistentUpdate) {
// 声音为true
beep = true;
} else {
if (isInCall()) {
playInCallNotification();
beep = true;
} else {
//播放声音返回结果
beep = playSound(record, soundUri);
}
if (beep) {
mSoundNotificationKey = key;
}
}
}
final boolean ringerModeSilent =
mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_SILENT;
//非通话中,有设置震动,非静音模式
if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
if (isInsistentUpdate) {
buzz = true;
} else {
//震动
buzz = playVibration(record, vibration, hasValidSound);
if (buzz) {
mVibrateNotificationKey = key;
}
}
}
} else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
hasValidSound = false;
}
}
}
//旧通知有声音,新的没有
if (wasBeep && !hasValidSound) {
//停止声音播放
clearSoundLocked();
}
//同上
if (wasBuzz && !hasValidVibrate) {
//停止震动
clearVibrateLocked();
}
//旧的light状态
boolean wasShowLights = mLights.remove(key);
//见4.4,是否可以闪灯
if (canShowLightsLocked(record, aboveThreshold)) {
//加入集合
mLights.add(key);
//见4.6,闪灯或者灭灯
updateLightsLocked();
//mUseAttentionLight:只有当设备具有单独的注意灯和通知灯时,才将此设置为true,默认false
if (mUseAttentionLight && mAttentionLight != null) {
//如果支持提示灯并且不为空的话,见7.1.4
mAttentionLight.pulse();
}
blink = true;
} else if (wasShowLights) {
updateLightsLocked();
}
//3种状态封装成一个int
final int buzzBeepBlink = (buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0);
if (buzzBeepBlink > 0) {
// 忽略摘要更新,因为我们不会显示大部分信息
if (record.getSbn().isGroup() && record.getSbn().getNotification().isGroupSummary()) {
} else if (record.canBubble()) {
} else {
record.setInterruptive(true);
}
//为true记录下震动或声音的开始时间,为false,时间为-1
record.setAudiblyAlerted(buzz || beep);
return buzzBeepBlink;
}
>2.isCritical
是否是紧急通知,默认的critical是normal=2,还有个0和1就是紧急的
private boolean isCritical(NotificationRecord record) {
// 0 is the most critical
return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
}
>3.shouldMuteNotificationLocked
通知是否应该静默的
boolean shouldMuteNotificationLocked(final NotificationRecord record) {
final Notification notification = record.getNotification();
if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
//通知更新,并且限制只提示一次
return true;
}
// Suppressed because a user manually unsnoozed something (or similar)
if (record.shouldPostSilently()) {
return true;
}
// muted by listener,见补充4
final String disableEffects = disableNotificationEffects(record);
if (disableEffects != null) {
ZenLog.traceDisableEffects(record, disableEffects);
return true;
}
// suppressed due to DND
if (record.isIntercepted()) {
return true;
}
// Suppressed because another notification in its group handles alerting
if (record.getSbn().isGroup()) {
if (notification.suppressAlertingDueToGrouping()) {
return true;
}
}
// Suppressed for being too recently noisy
final String pkg = record.getSbn().getPackageName();
if (mUsageStats.isAlertRateLimited(pkg)) {
Slog.e(TAG, "Muting recently noisy " + record.getKey());
return true;
}
// A different looping ringtone, such as an incoming call is playing
if (isCurrentlyInsistent() && !isInsistentUpdate(record)) {
return true;
}
// Suppressed since it's a non-interruptive update to a bubble-suppressed notification
final boolean isBubbleOrOverflowed = record.canBubble() && (record.isFlagBubbleRemoved()
|| record.getNotification().isBubbleNotification());
if (record.isUpdate && !record.isInterruptive() && isBubbleOrOverflowed
&& record.getNotification().getBubbleMetadata() != null) {
if (record.getNotification().getBubbleMetadata().isNotificationSuppressed()) {
return true;
}
}
return false;
}
>4.disableNotificationEffects
- mListenerHints是NotificationListenerService.java里设置的,暂时没找到哪里用到
private String disableNotificationEffects(NotificationRecord record) {
if (mDisableNotificationEffects) {
//一种是setupwizard还没完成,一种是状态栏disable了通知
return "booleanState";
}
if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
return "listenerHints";
}
if (record != null && record.getAudioAttributes() != null) {
if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
if (record.getAudioAttributes().getUsage()
!= AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
return "listenerNoti";
}
}
if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
if (record.getAudioAttributes().getUsage()
== AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
return "listenerCall";
}
}
}
if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
return "callState";
}
return null;
}
4.4.canShowLightsLocked
返回通知是否支持led灯
boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
if (!mHasLight) {
//配置不支持light,补充1
return false;
}
//Settings.System.NOTIFICATION_LIGHT_PULSE的值,默认是true的
if (!mNotificationPulseEnabled) {
return false;
}
//见5.1.5,用户enableShowLight才不为空
if (record.getLight() == null) {
return false;
}
// 不重要的通知
if (!aboveThreshold) {
return false;
}
// 勿扰模式限制
if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
return false;
}
// Suppressed because it's a silent update
final Notification notification = record.getNotification();
if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
return false;
}
// Suppressed because another notification in its group handles alerting
if (record.getSbn().isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
return false;
}
// not if in call
if (isInCall()) {
return false;
}
// check current user
if (!isNotificationForCurrentUser(record)) {
return false;
}
// Light, but only when the screen is off
return true;
}
>1.mHasLight
mHasLight =
resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
>2.mNotificationPulseEnabled
boolean mNotificationPulseEnabled;
监听Settings.System.NOTIFICATION_LIGHT_PULSE的值,打印了下是1
if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
!= 0;
if (mNotificationPulseEnabled != pulseEnabled) {
mNotificationPulseEnabled = pulseEnabled;
updateNotificationPulse();
}
}
4.5.mIntentReceiver
- 跟踪屏幕的开/关状态,但不要关闭通知灯直到用户通过锁屏或下拉查看通知
- 如下3种,屏幕点亮,熄灭以及通话状态的改变,会更新通知灯的状态
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_ON)) {
mScreenOn = true;
updateNotificationPulse();//见补充1
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
mScreenOn = false;
updateNotificationPulse();
} else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
.equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
updateNotificationPulse();
}
>1.updateNotificationPulse
private void updateNotificationPulse() {
synchronized (mNotificationLock) {
//见4.6
updateLightsLocked();
}
}
4.6.updateLightsLocked
更新通知灯的状态
void updateLightsLocked()
{
if (mNotificationLight == null) {
return;
}
//通过lights查找对应的通知,没找到的话从集合里删除
NotificationRecord ledNotification = null;
while (ledNotification == null && !mLights.isEmpty()) {
//找到最新的一个通知
final String owner = mLights.get(mLights.size() - 1);
ledNotification = mNotificationsByKey.get(owner);
if (ledNotification == null) {
mLights.remove(owner);
}
}
//没有需要led的通知,或者通话中,或者屏幕点亮
if (ledNotification == null || isInCall() || mScreenOn) {
//关闭led,见7.1.2
mNotificationLight.turnOff();
} else {
NotificationRecord.Light light = ledNotification.getLight();
if (light != null && mNotificationPulseEnabled) {
//led开始脉冲,见7.1.1
mNotificationLight.setFlashing(light.color, LogicalLight.LIGHT_FLASH_TIMED,
light.onMs, light.offMs);
}
}
}
4.7.canUseManagedServices
- 包的权限检查,如果没有要检查的权限,则返回true
- mAllowedManagedServicePackages会调用test方法,就是这个方法
// Needs to be set before loadPolicyFile
mAllowedManagedServicePackages = this::canUseManagedServices;
boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
boolean canUseManagedServices = true;
if (requiredPermission != null) {
try {
if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
!= PackageManager.PERMISSION_GRANTED) {
canUseManagedServices = false;
}
}
}
return canUseManagedServices;
}
4.8.handleSavePolicyFile
这个就是保存policy数据到文件的方法,几十个地方调用,就不看了。
protected void handleSavePolicyFile() {
if (!IoThread.getHandler().hasCallbacks(mSavePolicyFile)) {
IoThread.getHandler().postDelayed(mSavePolicyFile, 250);
}
}
4.9.loadPolicyFile
- init方法里调用
- 首次加载会走catch方法里,第一次文件肯定不存在,catch里会加载默认数据
protected void loadPolicyFile() {
synchronized (mPolicyFile) {
InputStream infile = null;
try {
infile = mPolicyFile.openRead();
//见4.10,解析数据
readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
} catch (FileNotFoundException e) {
//第一次的话文件没找到,加载默认的允许的管理服务,见补充1
loadDefaultApprovedServices(USER_SYSTEM);
//补充2,末尾会保存文件,之后就不会走到这个异常里了
allowDefaultApprovedServices(USER_SYSTEM);
}
}
}
>1.loadDefaultApprovedServices
void loadDefaultApprovedServices(int userId) {
//见9.5
mListeners.loadDefaultsFromConfig();
mConditionProviders.loadDefaultsFromConfig();
//见10.5
mAssistants.loadDefaultsFromConfig();
}
>2.allowDefaultApprovedServices
protected void allowDefaultApprovedServices(int userId) {
//数据就是补充1里加载的,见9.5.1里的配置
ArraySet<ComponentName> defaultListeners = mListeners.getDefaultComponents();
for (int i = 0; i < defaultListeners.size(); i++) {
ComponentName cn = defaultListeners.valueAt(i);
//最终会走2.3,再到11.8,加入approved集合
allowNotificationListener(userId, cn);
}
//这个配置的是DND勿扰模式下允许的包,
ArraySet<String> defaultDnds = mConditionProviders.getDefaultPackages();
for (int i = 0; i < defaultDnds.size(); i++) {
allowDndPackage(userId, defaultDnds.valueAt(i));
}
setDefaultAssistantForUser(userId);
}
4.10.readPolicyXml
void readPolicyXml(InputStream stream, boolean forRestore, int userId)
throws XmlPullParserException, NumberFormatException, IOException {
//..
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
mZenModeHelper.readXml(parser, forRestore, userId);
} else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
mPreferencesHelper.readXml(parser, forRestore, userId);
}
if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
if (ineligibleForManagedServices) {
continue;
}
mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
} else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
if (ineligibleForManagedServices) {
continue;
}
//解析数据
mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
} else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
if (ineligibleForManagedServices) {
continue;
}//解析数据
mConditionProviders.readXml(
parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
} else if (mSnoozeHelper.XML_TAG_NAME.equals(parser.getName())) {
mSnoozeHelper.readXml(parser, System.currentTimeMillis());
}
if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
if (forRestore && userId != UserHandle.USER_SYSTEM) {
continue;
}
mLockScreenAllowSecureNotifications = parser.getAttributeBoolean(null,
LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE, true);
}
}
if (!migratedManagedServices) {
mListeners.migrateToXml();
mAssistants.migrateToXml();
mConditionProviders.migrateToXml();
handleSavePolicyFile();
}
mAssistants.resetDefaultAssistantsIfNecessary();
}
5.NotificationRecord.java
- 学习下通知相关的声音,震动,灯光等默认值,以及key
5.1.构造方法
public NotificationRecord(Context context, StatusBarNotification sbn,
NotificationChannel channel) {
this.sbn = sbn;
mTargetSdkVersion = LocalServices.getService(PackageManagerInternal.class)
.getPackageTargetSdkVersion(sbn.getPackageName());
mAm = ActivityManager.getService();
mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);
mOriginalFlags = sbn.getNotification().flags;
mRankingTimeMs = calculateRankingTimeMs(0L);
mCreationTimeMs = sbn.getPostTime();
mUpdateTimeMs = mCreationTimeMs;
mInterruptionTimeMs = mCreationTimeMs;
mContext = context;
stats = new NotificationUsageStats.SingleNotificationStats();
mChannel = channel;
//api26才添加的channel,这里判断是否是26以前的版本,肯定是false
mPreChannelsNotification = isPreChannelsNotification();
mSound = calculateSound();//补充1
mVibration = calculateVibration();//补充2
mAttributes = calculateAttributes();//补充3
mImportance = calculateInitialImportance();//补充4
mLight = calculateLights();//补充5
mAdjustments = new ArrayList<>();
mStats = new NotificationStats();
calculateUserSentiment();
calculateGrantableUris();
}
>1.calculateSound
通知声音获取
private Uri calculateSound() {
final Notification n = getSbn().getNotification();
// tv不支持通知
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
return null;
}
//获取channel里的声音uri,这个是有默认值的
Uri sound = mChannel.getSound();
//..
return sound;
}
2.calculateVibration
通知震动
private VibrationEffect calculateVibration() {
VibratorHelper helper = new VibratorHelper(mContext);
final Notification notification = getSbn().getNotification();
final boolean insistent = (notification.flags & Notification.FLAG_INSISTENT) != 0;
//获取默认的震动效果
VibrationEffect defaultVibration = helper.createDefaultVibration(insistent);
VibrationEffect vibration;
//获取channel里设置的是否需要震动
if (getChannel().shouldVibrate()) {
//没有设置震动模式的话,用默认的
//有设置的话就生成一个新的
vibration = getChannel().getVibrationPattern() == null
? defaultVibration
: helper.createWaveformVibration(getChannel().getVibrationPattern(), insistent);
} else {//不需要震动
vibration = null;
}
//..
return vibration;
}
>3.calculateAttributes
private AudioAttributes calculateAttributes() {
final Notification n = getSbn().getNotification();
AudioAttributes attributes = getChannel().getAudioAttributes();
if (attributes == null) {
attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
}
//..
return attributes;
}
>4.calculateInitialImportance
private int calculateInitialImportance() {
final Notification n = getSbn().getNotification();
//获取channel设置的重要性
int importance = getChannel().getImportance();
mInitialImportanceExplanationCode = getChannel().hasUserSetImportance()
? MetricsEvent.IMPORTANCE_EXPLANATION_USER
: MetricsEvent.IMPORTANCE_EXPLANATION_APP;
//flag转化成优先级
if (0 != (n.flags & Notification.FLAG_HIGH_PRIORITY)) {
n.priority = Notification.PRIORITY_MAX;
}
int requestedImportance = IMPORTANCE_DEFAULT;
n.priority = NotificationManagerService.clamp(n.priority, Notification.PRIORITY_MIN,
Notification.PRIORITY_MAX);
//转化通知里的priority为和channel里一样的重要性
switch (n.priority) {
case Notification.PRIORITY_MIN:
requestedImportance = IMPORTANCE_MIN;
break;
case Notification.PRIORITY_LOW:
requestedImportance = IMPORTANCE_LOW;
break;
case Notification.PRIORITY_DEFAULT:
requestedImportance = IMPORTANCE_DEFAULT;
break;
case Notification.PRIORITY_HIGH:
case Notification.PRIORITY_MAX:
requestedImportance = IMPORTANCE_HIGH;
break;
}
stats.requestedImportance = requestedImportance;
stats.isNoisy = mSound != null || mVibration != null;
//..
stats.naturalImportance = importance;
return importance;
}
>5.calculateLights
private Light calculateLights() {
//获取默认的灯光颜色以及开关时间
int defaultLightColor = mContext.getResources().getColor(
com.android.internal.R.color.config_defaultNotificationColor);
int defaultLightOn = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOn);
int defaultLightOff = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultNotificationLedOff);
int channelLightColor = getChannel().getLightColor() != 0 ? getChannel().getLightColor()
: defaultLightColor;
//enableShowLights的话才创建light对象
Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
defaultLightOn, defaultLightOff) : null;
//.
return light;
}
5.2.getKey
public String getKey() { return getSbn().getKey(); }//6.1.1
6.StatusBarNotification
- 主要学习下key和groupKey的获取,这个是区分通知的标志
6.1.构造方法
public StatusBarNotification(String pkg, String opPkg, int id,
String tag, int uid, int initialPid, Notification notification, UserHandle user,
String overrideGroupKey, long postTime) {
if (pkg == null) throw new NullPointerException();
if (notification == null) throw new NullPointerException();
this.pkg = pkg;
this.opPkg = opPkg;
this.id = id;
this.tag = tag;
this.uid = uid;
this.initialPid = initialPid;
this.notification = notification;
this.user = user;
this.postTime = postTime;
this.overrideGroupKey = overrideGroupKey;
this.key = key();//补充1
this.groupKey = groupKey();//补充2
}
>1.key
- 可以看到key是一堆唯一的表示组合到一起的字符串
private String key() {
String sbnKey = user.getIdentifier() + "|" + pkg + "|" + id + "|" + tag + "|" + uid;
if (overrideGroupKey != null && getNotification().isGroupSummary()) {
sbnKey = sbnKey + "|" + overrideGroupKey;
}
return sbnKey;
}
>2.groupKey
private String groupKey() {
if (overrideGroupKey != null) {
return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey;
}
final String group = getNotification().getGroup();
final String sortKey = getNotification().getSortKey();
//这两个默认是空的,除非你手动设置
if (group == null && sortKey == null) {
// 所以默认情况下用的这个
return key;
}
//默认情况下,groupKey 和user,pkg以及channelId有关。
return user.getIdentifier() + "|" + pkg + "|" +
(group == null
? "c:" + notification.getChannelId()
: "g:" + group);
}
7.LightsService.java
7.1.LightImpl
private final class LightImpl extends LogicalLight {
>1.setFlashing
public void setFlashing(int color, int mode, int onMS, int offMS) {
synchronized (this) {
//见补充3
setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER);
}
}
>2.turnOff
public void turnOff() {
synchronized (this) {
setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0);
}
}
>3.setLightLocked
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
if (shouldBeInLowPersistenceMode()) {//vr有关的,为false
brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
} else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
brightnessMode = mLastBrightnessMode;
}
//以下任何一种发生变化,都重新设置light
if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
offMS != mOffMS || mBrightnessMode != brightnessMode) {
mInitialized = true;
mLastColor = mColor;
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
mBrightnessMode = brightnessMode;
setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
}
}
>4.pulse
脉冲闪灯,这里用的是硬件,默认的闪白光,才7毫秒就被stop了。。
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.postDelayed(this::stopFlashing, onMS);
}
}
}
private void stopFlashing() {
synchronized (this) {
setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);
}
}
8.NotificationChannel.java
8.1.创建
- 下边是自己写的demo
- 构造方法3个参数,唯一个id,名字,以及重要性
- 以前没有channel的时候,通知的灯光震动灯都是自己设置的,现在方法都过期了,需要在channel里设置
private fun createChannel(groupID: String?,
groupName: String?,
channelID: String,
channelName: String,
channelDes: String) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
//channelId要唯一
val adChannel = NotificationChannel(channelID, channelName, NotificationManager.IMPORTANCE_DEFAULT).apply {
//补充channel的含义(可选)
description = channelDes
//默认是true,在app的logo右上角有个圆点,而且长按logo还能看到最新一条通知
setShowBadge(true)
//灯光
enableLights(true)
//led灯的颜色设置
lightColor = Color.RED
//震动
enableVibration(false)
}
//将渠道添加进组(先创建组才能添加)
groupID?.apply {
//分组(可选)
notificationManager.createNotificationChannelGroup(NotificationChannelGroup(this, groupName))
adChannel.group = groupID
}
//创建channel
notificationManager.createNotificationChannel(adChannel)
}
8.2.Notification.java
>1.创建
- 正常都是通过Builder创建的
private fun createNotificationWithChannel(channelID: String, title: String, content: String, id: Int) {
var builder: Notification.Builder = Notification.Builder(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//创建通知时,标记你的渠道id
builder = Notification.Builder(this, channelID)
// builder.setTimeoutAfter(1 * 60 * 1000)//1分钟后自动消失
}
val notification = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
builder.setSmallIcon(R.drawable.ic_lock).setLargeIcon(Icon.createWithResource(this, R.drawable.my_alram))
.setContentTitle("This is $title")
.setContentText("content:$content")
.setAutoCancel(false).build()
}
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.notify(id, notification)
}
>2.setGroup
.setGroup(group)
.setGroupSummary(true)
- 没有设置group的时候,一个应用里发出的通知会会在一个群组里,如下图

- 设置了group以后,不同group显示在不同的群组里,同样的group一次只能看到一个,新的删除才能看到旧的。如下图

9.NotificationListeners
- 小节4 NMS的内部类
public class NotificationListeners extends ManagedServices {
9.1.getConfig
protected Config getConfig() {
Config c = new Config();
c.caption = "notification listener";
c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
c.clientLabel = R.string.notification_listener_binding_label;
return c;
}
9.2.onServiceAdded
public void onServiceAdded(ManagedServiceInfo info) {
final INotificationListener listener = (INotificationListener) info.service;
final NotificationRankingUpdate update;
synchronized (mNotificationLock) {
update = makeRankingUpdateLocked(info);
updateUriPermissionsForActiveNotificationsLocked(info, true);
}
try {
listener.onListenerConnected(update);
}
}
9.3.getBindFlags
protected int getBindFlags() {
return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
| BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
}
9.4.getRequiredPermission
protected String getRequiredPermission() {
return null;
}
9.5.loadDefaultsFromConfig
protected void loadDefaultsFromConfig() {
String defaultListenerAccess = mContext.getResources().getString(
R.string.config_defaultListenerAccessPackages);
if (defaultListenerAccess != null) {
String[] listeners =
defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR);
for (int i = 0; i < listeners.length; i++) {
if (TextUtils.isEmpty(listeners[i])) {
continue;
}
int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
if (mIsHeadlessSystemUserMode) {
packageQueryFlags += MATCH_ANY_USER;
}
ArraySet<ComponentName> approvedListeners =
this.queryPackageForServices(listeners[i], packageQueryFlags,
USER_SYSTEM);
for (int k = 0; k < approvedListeners.size(); k++) {
ComponentName cn = approvedListeners.valueAt(k);
//见11.9加入默认包或者组件集合里
addDefaultComponentOrPackage(cn.flattenToString());
}
}
}
}
>1.config_defaultListenerAccessPackages
AOSP里是空的,GMS里有配置
<string name="config_defaultListenerAccessPackages" translatable="false">com.android.launcher3:com.google.android.projection.gearhead</string>
10.NotificationAssistants
- 小节4 NMS的内部类
public class NotificationAssistants extends ManagedServices {
10.1.onUserUnlocked
@Override
public void onUserUnlocked(int user) {
rebindServices(true, user);
}
10.2.getConfig()
protected Config getConfig() {
Config c = new Config();
c.caption = "notification assistant";
c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
c.clientLabel = R.string.notification_ranker_binding_label;
return c;
}
10.3.onServiceAdded
- mListeners就是小节9的实例
protected void onServiceAdded(ManagedServiceInfo info) {
//父类小节11里实现的,
mListeners.registerGuestService(info);
}
10.4.getRequiredPermission
protected String getRequiredPermission() {
// only signature/privileged apps can be bound.
return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
}
10.5.loadDefaultsFromConfig
protected void loadDefaultsFromConfig() {
loadDefaultsFromConfig(true);
}
protected void loadDefaultsFromConfig(boolean addToDefault) {
ArraySet<String> assistants = new ArraySet<>();
assistants.addAll(Arrays.asList(mContext.getResources().getString(
com.android.internal.R.string.config_defaultAssistantAccessComponent)
.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)));
for (int i = 0; i < assistants.size(); i++) {
ComponentName assistantCn = ComponentName
.unflattenFromString(assistants.valueAt(i));
String packageName = assistants.valueAt(i);
if (assistantCn != null) {
packageName = assistantCn.getPackageName();
}
if (TextUtils.isEmpty(packageName)) {
continue;
}
ArraySet<ComponentName> approved = queryPackageForServices(packageName,
MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM);
if (approved.contains(assistantCn)) {
if (addToDefault) {
//见11.9
addDefaultComponentOrPackage(assistantCn.flattenToString());
} else {
// otherwise, store in the mDefaultFromConfig for NAS settings migration
mDefaultFromConfig = assistantCn;
}
}
}
}
>1.config_defaultAssistantAccessComponent
GMS覆写的
<string name="config_defaultAssistantAccessComponent" translatable="false">com.google.android.ext.services/android.ext.services.notification.Assistant</string>
默认的
<string name="config_defaultAssistantAccessComponent" translatable="false">android.ext.services/android.ext.services.notification.Assistant</string>
11.ManagedServices.java
11.1.rebindServices
- 当用户改变(切换,添加,删除等),或者包改变(新加,删除,状态变化等),或者安全设置改变等都会调用这个
protected void rebindServices(boolean forceRebind, int userToRebind) {
//先获取所有用户id
IntArray userIds = mUserProfiles.getCurrentProfileIds();
//如果指定要rebind的用户id不是ALL
if (userToRebind != USER_ALL) {
//那么就使用这个指定的用户id
userIds = new IntArray(1);
userIds.add(userToRebind);
}
//要绑定的组件集合
final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
//要解除绑定的组件集合
final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
synchronized (mMutex) {
//见补充1,获取可用的组件
final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
getAllowedComponents(userIds);
//获取可移除的服务信息
final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
//见补充2过滤下冻结的数据
populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
//见补充3
populateComponentsToUnbind(
forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
}
unbindFromServices(componentsToUnbind);
bindToServices(componentsToBind);
}
>1.getAllowedComponents
protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
final int nUserIds = userIds.size();
final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
for (int i = 0; i < nUserIds; ++i) {
final int userId = userIds.get(i);
synchronized (mApproved) {
//可以看到数据是从map里读取的,后边查看mApproved数据来源
final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
if (approvedLists != null) {
final int N = approvedLists.size();
for (int j = 0; j < N; j++) {
ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
if (approvedByUser == null) {
approvedByUser = new ArraySet<>();
componentsByUser.put(userId, approvedByUser);
}
approvedByUser.addAll(
loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
}
}
}
}
return componentsByUser;
}
>2.populateComponentsToBind
数据过滤下
protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
final IntArray activeUsers,
SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
mEnabledServicesForCurrentProfiles.clear();
mEnabledServicesPackageNames.clear();
final int nUserIds = activeUsers.size();
for (int i = 0; i < nUserIds; ++i) {
// decode the list of components
final int userId = activeUsers.get(i);
final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
if (null == userComponents) {
componentsToBind.put(userId, new ArraySet<>());
continue;
}
final Set<ComponentName> add = new HashSet<>(userComponents);
//移除了冻结的数据
add.removeAll(mSnoozingForCurrentProfiles);
//最终的数据就是移除后的
componentsToBind.put(userId, add);
//这里记录的是可用的组件
mEnabledServicesForCurrentProfiles.addAll(userComponents);
for (int j = 0; j < userComponents.size(); j++) {
final ComponentName component = userComponents.valueAt(j);
//可用的包名
mEnabledServicesPackageNames.add(component.getPackageName());
}
}
}
>3.populateComponentsToUnbind
protected void populateComponentsToUnbind(
boolean forceRebind,
Set<ManagedServiceInfo> removableBoundServices,
SparseArray<Set<ComponentName>> allowedComponentsToBind,
SparseArray<Set<ComponentName>> componentsToUnbind) {
//循环所有可移除的info
for (ManagedServiceInfo info : removableBoundServices) {
//获取允许绑定的组件
final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
if (allowedComponents != null) {
//强制重新绑定,或者 不在允许绑定的集合里
if (forceRebind || !allowedComponents.contains(info.component)) {
//那就放入要unbind的集合里
Set<ComponentName> toUnbind =
componentsToUnbind.get(info.userid, new ArraySet<>());
toUnbind.add(info.component);
componentsToUnbind.put(info.userid, toUnbind);
}
}
}
}
11.2.bindToServices
private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
for (int i = 0; i < componentsToBind.size(); i++) {
final int userId = componentsToBind.keyAt(i);
final Set<ComponentName> add = componentsToBind.get(userId);
for (ComponentName component : add) {
try {
//根据组件信息获取服务信息
ServiceInfo info = mPm.getServiceInfo(component,
PackageManager.GET_META_DATA
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
userId);
if (info == null) {
continue;
}
if (!mConfig.bindPermission.equals(info.permission)) {
//权限不满足
continue;
}
registerService(info, userId);
}
}
}
>1.registerService
void registerService(final ServiceInfo si, final int userId) {
ensureFilters(si, userId);
registerService(si.getComponentName(), userId);
}
void registerService(final ComponentName cn, final int userId) {
synchronized (mMutex) {
registerServiceLocked(cn, userId);
}
}
void reregisterService(final ComponentName cn, final int userId) {
//先判断下组件或者包是否可用,万一被disable了
if (isPackageOrComponentAllowed(cn.getPackageName(), userId)
|| isPackageOrComponentAllowed(cn.flattenToString(), userId)) {
registerService(cn, userId);
}
}
void registerService(final ComponentName cn, final int userId) {
synchronized (mMutex) {
registerServiceLocked(cn, userId);
}
}
private void registerServiceLocked(final ComponentName name, final int userid) {
//补充2
registerServiceLocked(name, userid, false /* isSystem */);
}
>2.registerServiceLocked
private void registerServiceLocked(final ComponentName name, final int userid,
final boolean isSystem) {
final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid);
if (mServicesBound.contains(servicesBindingTag)) {
//已经注册了
return;
}
//新注册的,加入集合
mServicesBound.add(servicesBindingTag);
final int N = mServices.size();
for (int i = N - 1; i >= 0; i--) {
final ManagedServiceInfo info = mServices.get(i);
if (name.equals(info.component)
&& info.userid == userid) {
//有旧的,先断开
removeServiceLocked(i);
if (info.connection != null) {
unbindService(info.connection, info.component, info.userid);
}
}
}
//具体的action见9.1和10.2
Intent intent = new Intent(mConfig.serviceInterface);
intent.setComponent(name);
intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
final PendingIntent pendingIntent = PendingIntent.getActivity(
mContext, 0, new Intent(mConfig.settingsAction), PendingIntent.FLAG_IMMUTABLE);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
ApplicationInfo appInfo = null;
try {
appInfo = mContext.getPackageManager().getApplicationInfo(
name.getPackageName(), 0);
} catch (NameNotFoundException e) {
// Ignore if the package doesn't exist we won't be able to bind to the service.
}
final int targetSdkVersion =
appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
final int uid = appInfo != null ? appInfo.uid : -1;
try {
//下边就是绑定服务的回调了
ServiceConnection serviceConnection = new ServiceConnection() {
IInterface mService;
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
boolean added = false;
ManagedServiceInfo info = null;
synchronized (mMutex) {
mServicesRebinding.remove(servicesBindingTag);
try {
mService = asInterface(binder);
//绑定成功以后封装一个info
info = newServiceInfo(mService, name,
userid, isSystem, this, targetSdkVersion, uid);
binder.linkToDeath(info, 0);
//加入集合
added = mServices.add(info);
}
}
if (added) {
//新加的服务
onServiceAdded(info);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onBindingDied(ComponentName name) {
synchronized (mMutex) {
unbindService(this, name, userid);
if (!mServicesRebinding.contains(servicesBindingTag)) {
mServicesRebinding.add(servicesBindingTag);
mHandler.postDelayed(() ->
reregisterService(name, userid),
ON_BINDING_DIED_REBIND_DELAY_MS);
}
}
}
@Override
public void onNullBinding(ComponentName name) {
mContext.unbindService(this);
}
};
//开始绑定服务
if (!mContext.bindServiceAsUser(intent,
serviceConnection,
getBindFlags(),
new UserHandle(userid))) {
mServicesBound.remove(servicesBindingTag);
return;
}
} catch (SecurityException ex) {
mServicesBound.remove(servicesBindingTag);
}
}
子类可以重写,见9.3
protected int getBindFlags() {
return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT;
}
11.3.记录下开机后rebindService
看下都哪里调用了11.1的方法
>1.onStart
//见11.7.1末尾
at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
//见4.10
at com.android.server.notification.ManagedServices.readXml(ManagedServices.java:700)
at com.android.server.notification.NotificationManagerService.readPolicyXml(NotificationManagerService.java:971)
at com.android.server.notification.NotificationManagerService.loadPolicyFile(NotificationManagerService.java:1015)
at com.android.server.notification.NotificationManagerService.init(NotificationManagerService.java:2343)
at com.android.server.notification.NotificationManagerService.onStart(NotificationManagerService.java:2512)
at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:258)
at com.android.server.SystemServiceManager.startService(SystemServiceManager.java:236)
at com.android.server.SystemServer.startOtherServices(SystemServer.java:2062)
at com.android.server.SystemServer.run(SystemServer.java:941)
>2.resetDefaultAssistantsIfNecessary
at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
at com.android.server.notification.ManagedServices.setPackageOrComponentEnabled(ManagedServices.java:831)
at com.android.server.notification.ManagedServices.setPackageOrComponentEnabled(ManagedServices.java:791)
at com.android.server.notification.NotificationManagerService.setNotificationAssistantAccessGrantedForUserInternal(NotificationManagerService.java:5809)
at com.android.server.notification.NotificationManagerService.allowAssistant(NotificationManagerService.java:940)
at com.android.server.notification.NotificationManagerService.setDefaultAssistantForUser(NotificationManagerService.java:875)
at com.android.server.notification.NotificationManagerService$NotificationAssistants.resetDefaultAssistantsIfNecessary(NotificationManagerService.java:10671)
at com.android.server.notification.NotificationManagerService.readPolicyXml(NotificationManagerService.java:1005)
at com.android.server.notification.NotificationManagerService.loadPolicyFile(NotificationManagerService.java:1015)
at com.android.server.notification.NotificationManagerService.init(NotificationManagerService.java:2343)
at com.android.server.notification.NotificationManagerService.onStart(NotificationManagerService.java:2512)
>3.onUserSwitched
at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
at com.android.server.notification.ManagedServices.onUserSwitched(ManagedServices.java:984)
at com.android.server.notification.NotificationManagerService$6.onReceive(NotificationManagerService.java:1838)
>4.onUserUnlocked
at com.android.server.notification.ManagedServices.rebindServices(ManagedServices.java:1361)
at com.android.server.notification.NotificationManagerService$NotificationAssistants.onUserUnlocked(NotificationManagerService.java:10276)
at com.android.server.notification.NotificationManagerService$6.onReceive(NotificationManagerService.java:1864)
11.4日志相关的代码
NotificationManagerService.java
>1.readPolicyXml
参考11.3.1日志
void readPolicyXml(InputStream stream, boolean forRestore, int userId)
//...
if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
if (ineligibleForManagedServices) {
continue;
}
//这个是小节9实例
mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
} else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
if (ineligibleForManagedServices) {
continue;
}
//这个是小节10实例
mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
migratedManagedServices = true;
} else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
if (ineligibleForManagedServices) {
continue;
}
//这个的log也是11.3.1
mConditionProviders.readXml(
parser, mAllowedManagedServicePackages, forRestore, userId);
migratedManagedServices = true;
}
//...
//log见11.3.2
mAssistants.resetDefaultAssistantsIfNecessary();
}
文件路径 /data/system/notification_policy.xml
new AtomicFile(new File(
systemDir, "notification_policy.xml"), "notification-policy"),
>2.ACTION_USER_SWITCHED
具体实现见11.5
} else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
mUserProfiles.updateCache(context);
//非配置用户,默认启动会走这里的
if (!mUserProfiles.isProfileUser(userId)) {
// reload per-user settings
mSettingsObserver.update(null);
//这里两处调用,log见11.3.3
mConditionProviders.onUserSwitched(userId);
mListeners.onUserSwitched(userId);
mZenModeHelper.onUserSwitched(userId);
}
//这里也调用,log见11.3.3
mAssistants.onUserSwitched(userId);
}
>3.ACTION_USER_UNLOCKED
} else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
mUserProfiles.updateCache(context);
//log见11.3.4,方法见11.6
mAssistants.onUserUnlocked(userId);
if (!mUserProfiles.isProfileUser(userId)) {
mConditionProviders.onUserUnlocked(userId);
mListeners.onUserUnlocked(userId);
mZenModeHelper.onUserUnlocked(userId);
}
}
11.5.onUserSwitched
public void onUserSwitched(int user) {
unbindOtherUserServices(user);
rebindServices(true, user);
}
11.6.onUserUnlocked
public void onUserUnlocked(int user) {
rebindServices(false, user);
}
11.7.addApprovedList
- mApproved数据就是这里添加的,允许绑定为managed services的集合,第一层key是user,第二层key是true或者false也就是是否是isPrimary
- mUserSetServices用户显示的配置为可用或不可用的包或者组件集合
protected ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
protected ArrayMap<Integer, ArraySet<String>> mUserSetServices = new ArrayMap<>();
protected void addApprovedList(String approved, int userId, boolean isPrimary) {
addApprovedList(approved, userId, isPrimary, approved);
}
protected void addApprovedList(String approved, int userId, boolean isPrimary, String userSet) {
if (TextUtils.isEmpty(approved)) {
approved = "";
}
if (userSet == null) {
userSet = approved;
}
synchronized (mApproved) {
ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
if (approvedByType == null) {
approvedByType = new ArrayMap<>();
mApproved.put(userId, approvedByType);
}
ArraySet<String> approvedList = approvedByType.get(isPrimary);
if (approvedList == null) {
approvedList = new ArraySet<>();
approvedByType.put(isPrimary, approvedList);
}
//数据用冒号分组
String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
for (String pkgOrComponent : approvedArray) {
String approvedItem = getApprovedValue(pkgOrComponent);
if (approvedItem != null) {
//是个有效的组件名,加入集合
approvedList.add(approvedItem);
}
}
ArraySet<String> userSetList = mUserSetServices.get(userId);
if (userSetList == null) {
userSetList = new ArraySet<>();
mUserSetServices.put(userId, userSetList);
}
//冒号分组
String[] userSetArray = userSet.split(ENABLED_SERVICES_SEPARATOR);
for (String pkgOrComponent : userSetArray) {
String approvedItem = getApprovedValue(pkgOrComponent);
if (approvedItem != null) {
userSetList.add(approvedItem);
}
}
}
}
下边贴下数据的来源
>1.readXml
读取配置里的数据
- 配置里的数据也是写入的,存的就是approved里的数据,那首次开机这数据哪里来的啊?
- 参考4.9,首次加载数据,文件不存在,就会读取默认的配置,完事保存文件。
public void readXml(
//..
if (type == XmlPullParser.START_TAG) {
if (TAG_MANAGED_SERVICES.equals(tag)) {//"service_listing"
//先读取配置里的数据
final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);//"approved"
//...
//test方法见4.7,权限见9.4以及10.4
if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
getPackageName(approved), resolvedUserId, getRequiredPermission())
|| approved.isEmpty()) {
if (mUm.getUserInfo(resolvedUserId) != null) {
//添加数据
addApprovedList(approved, resolvedUserId, isPrimary, userSetComponent);
}
mUseXml = true;
}
//... 见11.1 重新绑定服务,不强制
rebindServices(false, USER_ALL);
}
11.8.setPackageOrComponentEnabled
添加或者删除mApproved里的数据
protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
boolean isPrimary, boolean enabled, boolean userSet) {
synchronized (mApproved) {
ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
if (allowedByType == null) {
allowedByType = new ArrayMap<>();
mApproved.put(userId, allowedByType);
}
ArraySet<String> approved = allowedByType.get(isPrimary);
if (approved == null) {
approved = new ArraySet<>();
allowedByType.put(isPrimary, approved);
}
String approvedItem = getApprovedValue(pkgOrComponent);
if (approvedItem != null) {
if (enabled) {
approved.add(approvedItem);
} else {
approved.remove(approvedItem);
}
}
ArraySet<String> userSetServices = mUserSetServices.get(userId);
if (userSetServices == null) {
userSetServices = new ArraySet<>();
mUserSetServices.put(userId, userSetServices);
}
if (userSet) {
userSetServices.add(pkgOrComponent);
} else {
userSetServices.remove(pkgOrComponent);
}
}
rebindServices(false, userId);
}
11.9.addDefaultComponentOrPackage
protected void addDefaultComponentOrPackage(String packageOrComponent) {
if (!TextUtils.isEmpty(packageOrComponent)) {
synchronized (mDefaultsLock) {
if (mApprovalLevel == APPROVAL_BY_PACKAGE) {
mDefaultPackages.add(packageOrComponent);
return;
}
ComponentName cn = ComponentName.unflattenFromString(packageOrComponent);
if (cn != null && mApprovalLevel == APPROVAL_BY_COMPONENT) {
mDefaultPackages.add(cn.getPackageName());
mDefaultComponents.add(cn);
return;
}
}
}
}
12.总结
- 普通通知发送的流程比较简单,见2.1再到4.1,之后就是4.2和4.3
- 小节5到7,主要学习了通知相关的震动声音灯设置以及判定
- 另外学习下通知改变的监听服务NotificationListenerService如何默认启动,这是个抽象类,其他地方会继承这个类,主要是launcher里有用到这个,没看到服务咋启动的,这里学下。
- 4.9里首次读取配置的时候,会加载默认值,见4.9.1以及4.9.2,里边有分析走到2.3再走到11.8,数据加入了approved集合里。后续都是从配置文件里读取的。
- 11.3以及11.4里分析了rebind方法的调用,这个方法就是读取approved里的组件,进行bindService启动对应的服务。