NotificationMangerService处理显示通知
设置——>应用——>点击“已下载”列表中的任一APP,如图:
代码位置:Settings\src\com\android\settings\applications\InstalledAppDetails.java
//CheckBox显示通知处理
private void setNotificationsEnabled(boolean enabled) {
String packageName = mAppEntry.info.packageName;
INotificationManager nm = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
try {
final boolean enable = mNotificationSwitch.isChecked(); nm.setNotificationsEnabledForPackage(packageName, mAppEntry.info.uid, enabled);
} catch (android.os.RemoteException ex) {
mNotificationSwitch.setChecked(!enabled); // revert
}
}
INotificationManager 是通过AIDL处理,在java层就是NotificationMangerService处理。
android\frameworks\base\services\java\com\android\server\NotificationManagerService.java
public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
checkCallerIsSystem();//这里校验Uid检查调用程序有没有权限
Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg); mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED); // Now, cancel any outstanding notifications that are part of a just-disabled app
if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
}
}
校验Uid检查调用程序有没有权限,了解sharedUserId可以参考http://www.cnblogs.com/Ashia/articles/2474321.html
void checkCallerIsSystem() {
if (isCallerSystem()) {
return;
}
throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
} boolean isCallerSystem() {
return isUidSystem(Binder.getCallingUid());
} // Return true if the UID is a system or phone UID and therefore should not have
// any notifications or toasts blocked.
boolean isUidSystem(int uid) {
Slog.v(TAG, "isUidSystem , uid = " + uid);
final int appid = UserHandle.getAppId(uid);
return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
}
以上处理中mAppOps将需要处理的pkg做了标记,表示是否显示pkg发出的Notification
Notification的显示过程也是NotificationMangerService处理,在enqueueNotificationInternal(......)中处理,这里会判断pkg是否可以显示通知。
// Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
// uid/pid of another application) public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
final int callingPid, final String tag, final int id, final Notification notification,
int[] idOut, int incomingUserId)
{
if (DBG) {
Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
}
checkCallerIsSystemOrSameApp(pkg);
final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));//再次校验Uid
final int userId = ActivityManager.handleIncomingUser(callingPid,
callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
final UserHandle user = new UserHandle(userId); // Limit the number of notifications that any given package except the android
// package can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification) {
synchronized (mNotificationList) {
int count = 0;
final int N = mNotificationList.size();
for (int i=0; i<N; i++) {
final NotificationRecord r = mNotificationList.get(i);
if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
count++;
if (count >= MAX_PACKAGE_NOTIFICATIONS) {//判断允许的最大通知数
Slog.e(TAG, "Package has already posted " + count
+ " notifications. Not showing more. package=" + pkg);
return;
}
}
}
}
} // This conditional is a dirty hack to limit the logging done on
// behalf of the download manager without affecting other apps.
if (!pkg.equals("com.android.providers.downloads")
|| Log.isLoggable("DownloadManager", Log.VERBOSE)) {
EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag, userId,
notification.toString());
} if (pkg == null || notification == null) {
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
+ " id=" + id + " notification=" + notification);
}
if (notification.icon != 0) {
if (notification.contentView == null) {
throw new IllegalArgumentException("contentView required: pkg=" + pkg
+ " id=" + id + " notification=" + notification);
}
} mHandler.post(new Runnable() {
@Override
public void run() { // === Scoring === // 0. Sanitize inputs
notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
Notification.PRIORITY_MAX);
// Migrate notification flags to scores
if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
if (notification.priority < Notification.PRIORITY_MAX) {
notification.priority = Notification.PRIORITY_MAX;
}
} else if (SCORE_ONGOING_HIGHER &&
0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
if (notification.priority < Notification.PRIORITY_HIGH) {
notification.priority = Notification.PRIORITY_HIGH;
}
} // 1. initial score: buckets of 10, around the app
int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20] // 2. Consult external heuristics (TBD) // 3. Apply local rules int initialScore = score;
if (!mScorers.isEmpty()) {
if (DBG) Slog.v(TAG, "Initial score is " + score + ".");
for (NotificationScorer scorer : mScorers) {
try {
score = scorer.getScore(notification, score);
} catch (Throwable t) {
Slog.w(TAG, "Scorer threw on .getScore.", t);
}
}
if (DBG) Slog.v(TAG, "Final score is " + score + ".");
} // add extra to indicate score modified by NotificationScorer
notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED,
score != initialScore); // blocked apps
if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {//判断pkg是否可以显示通知
if (!isSystemNotification) {//不拦截系统通知
score = JUNK_SCORE; //在设置中禁止显示通知的pkg,会进到这里,JUNK_SCORE=-1000
Slog.e(TAG, "Suppressing notification from package " + pkg
+ " by user request.");
}
} if (DBG) {
Slog.v(TAG, "Assigned score=" + score + " to " + notification);
} if (score < SCORE_DISPLAY_THRESHOLD) {//进行"显示通知"拦截判断,SCORE_DIAPLAY_THRESHOLD=-20
// Notification will be blocked because the score is too low.
return; //完成拦截
}
// Should this notification make noise, vibe, or use the LED?
121 final boolean canInterrupt = (score >= SCORE_INTERRUPTION_THRESHOLD);
122
123 synchronized (mNotificationList) {
124 final StatusBarNotification n = new StatusBarNotification(
125 pkg, id, tag, callingUid, callingPid, score, notification, user);
126 NotificationRecord r = new NotificationRecord(n);
127 NotificationRecord old = null;
128
129 int index = indexOfNotificationLocked(pkg, tag, id, userId);
130 if (index < 0) {
131 mNotificationList.add(r);
132 } else {
133 old = mNotificationList.remove(index);
134 mNotificationList.add(index, r);
135 // Make sure we don't lose the foreground service state.
136 if (old != null) {
137 notification.flags |=
138 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
139 }
140 }
141
142 // Ensure if this is a foreground service that the proper additional
143 // flags are set.
144 if ((notification.flags&Notification.FLAG_FOREGROUND_SERVICE) != 0) {
145 notification.flags |= Notification.FLAG_ONGOING_EVENT
146 | Notification.FLAG_NO_CLEAR;
147 }
148
149 final int currentUser;
150 final long token = Binder.clearCallingIdentity();
151 try {
152 currentUser = ActivityManager.getCurrentUser();
153 } finally {
154 Binder.restoreCallingIdentity(token);
155 }
156
157 if (notification.icon != 0) {
158 if (old != null && old.statusBarKey != null) {
159 r.statusBarKey = old.statusBarKey;
160 long identity = Binder.clearCallingIdentity();
161 try {
162 mStatusBar.updateNotification(r.statusBarKey, n);
163 }
164 finally {
165 Binder.restoreCallingIdentity(identity);
166 }
167 } else {
168 long identity = Binder.clearCallingIdentity();
169 try {
170 r.statusBarKey = mStatusBar.addNotification(n);
171 if ((n.getNotification().flags & Notification.FLAG_SHOW_LIGHTS) != 0
172 && canInterrupt) {
173 mAttentionLight.pulse();
174 }
175 }
176 finally {
177 Binder.restoreCallingIdentity(identity);
178 }
179 }
180 // Send accessibility events only for the current user.
181 if (currentUser == userId) {
182 sendAccessibilityEvent(notification, pkg);
183 }
184
185 notifyPostedLocked(r);
186 } else {
187 Slog.e(TAG, "Not posting notification with icon==0: " + notification);
188 if (old != null && old.statusBarKey != null) {
189 long identity = Binder.clearCallingIdentity();
190 try {
191 mStatusBar.removeNotification(old.statusBarKey);
192 }
193 finally {
194 Binder.restoreCallingIdentity(identity);
195 }
196
197 notifyRemovedLocked(r);
198 }
199 // ATTENTION: in a future release we will bail out here
200 // so that we do not play sounds, show lights, etc. for invalid notifications
201 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
202 + n.getPackageName());
203 }
204
205 // Have ring tone when received SMS when the device is CT mode
206 boolean smsRingtone = mContext.getResources().getBoolean(
207 com.android.internal.R.bool.config_sms_ringtone_incall);
208
209 // If we're not supposed to beep, vibrate, etc. then don't.
210 if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS)
211 == 0 || (smsRingtone && mInCall))
212 && (!(old != null
213 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
214 && (r.getUserId() == UserHandle.USER_ALL ||
215 (r.getUserId() == userId && r.getUserId() == currentUser))
216 && canInterrupt
217 && mSystemReady) {
218
219 final AudioManager audioManager = (AudioManager) mContext
220 .getSystemService(Context.AUDIO_SERVICE);
221
222 // sound
223
224 // should we use the default notification sound? (indicated either by
225 // DEFAULT_SOUND or because notification.sound is pointing at
226 // Settings.System.NOTIFICATION_SOUND)
227 final boolean useDefaultSound =
228 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
229 Settings.System.DEFAULT_NOTIFICATION_URI
230 .equals(notification.sound);
231
232 Uri soundUri = null;
233 boolean hasValidSound = false;
234
235 if (useDefaultSound) {
236 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
237
238 // check to see if the default notification sound is silent
239 ContentResolver resolver = mContext.getContentResolver();
240 hasValidSound = Settings.System.getString(resolver,
241 Settings.System.NOTIFICATION_SOUND) != null;
242 } else if (notification.sound != null) {
243 soundUri = notification.sound;
244 hasValidSound = (soundUri != null);
245 }
246
247 if (hasValidSound) {
248 boolean looping = (notification.flags & Notification.FLAG_INSISTENT) != 0;
249 int audioStreamType;
250 if (notification.audioStreamType >= 0) {
251 audioStreamType = notification.audioStreamType;
252 } else {
253 audioStreamType = DEFAULT_STREAM_TYPE;
254 }
255 mSoundNotification = r;
256 // do not play notifications if stream volume is 0 (typically because
257 // ringer mode is silent) or if there is a user of exclusive audio focus
258 if ((audioManager.getStreamVolume(audioStreamType) != 0)
259 && !audioManager.isAudioFocusExclusive()) {
260 final long identity = Binder.clearCallingIdentity();
261 try {
262 final IRingtonePlayer player = mAudioService.getRingtonePlayer();
263 if (player != null) {
264 player.playAsync(soundUri, user, looping, audioStreamType);
265 }
266 } catch (RemoteException e) {
267 } finally {
268 Binder.restoreCallingIdentity(identity);
269 }
270 }
271 }
272
273 // vibrate
274 // Does the notification want to specify its own vibration?
275 final boolean hasCustomVibrate = notification.vibrate != null;
276
277 // new in 4.2: if there was supposed to be a sound and we're in vibrate
278 // mode, and no other vibration is specified, we fall back to vibration
279 final boolean convertSoundToVibration =
280 !hasCustomVibrate
281 && hasValidSound
282 && (audioManager.getRingerMode()
283 == AudioManager.RINGER_MODE_VIBRATE);
284
285 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
286 final boolean useDefaultVibrate =
287 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
288
289 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
290 && !(audioManager.getRingerMode()
291 == AudioManager.RINGER_MODE_SILENT)) {
292 mVibrateNotification = r;
293
294 if (useDefaultVibrate || convertSoundToVibration) {
295 // Escalate privileges so we can use the vibrator even if the
296 // notifying app does not have the VIBRATE permission.
297 long identity = Binder.clearCallingIdentity();
298 try {
299 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
300 useDefaultVibrate ? mDefaultVibrationPattern
301 : mFallbackVibrationPattern,
302 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
303 ? 0: -1);
304 } finally {
305 Binder.restoreCallingIdentity(identity);
306 }
307 } else if (notification.vibrate.length > 1) {
308 // If you want your own vibration pattern, you need the VIBRATE
309 // permission
310 mVibrator.vibrate(r.sbn.getUid(), r.sbn.getBasePkg(),
311 notification.vibrate,
312 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
313 ? 0: -1);
314 }
315 }
316 }
317
318 // light
319 // the most recent thing gets the light
320 mLights.remove(old);
321 if (mLedNotification == old) {
322 mLedNotification = null;
323 }
324 //Slog.i(TAG, "notification.lights="
325 // + ((old.notification.lights.flags & Notification.FLAG_SHOW_LIGHTS)
326 // != 0));
327 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0
328 && canInterrupt) {
329 mLights.add(r);
330 updateLightsLocked();
331 } else {
332 if (old != null
333 && ((old.getFlags() & Notification.FLAG_SHOW_LIGHTS) != 0)) {
334 updateLightsLocked();
335 }
336 }
337 }
338 }
339 });
340
341 idOut[0] = id;
342 }
NotificationMangerService处理显示通知的更多相关文章
- PendingIntent 显示通知
安卓显示通知 PendingIntent pendingIntent=PendingIntent.getActivity(Media.this,0, new Intent(Media.this,Med ...
- Android中使用Notification在状态栏上显示通知
场景 状态栏上显示通知效果 注: 博客: https://blog.csdn.net/badao_liumang_qizhi关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新 ...
- Android学习笔记使用Notication 显示通知
实现步骤 代码实现 创建MainActivity和DetailActivity(点击通知后要跳转的Activity),两个Activity的布局文件就是添加一张全屏的背景图,老规矩,不粘贴. Main ...
- Android开发之显示通知
Toast类可以用来显示消息给用户,虽然它很方便,但是有不能持久.它只是在屏幕上显示几秒后就自动消失掉了.对于重要的信息或消息,要使用更加持久的方法.这种情形下,就应当使用通知,即使用Notifica ...
- Ionic app 通知在Moto 360 Watch上显示通知(1)
手机与Moto 360 watch配对之后,watch上会接收到微信消息的通知,那么我们就可以利用这个特性开发一个App,在Watch显示我们自己的通知,具体过程如下 1.手机扫描二维码安装ticwa ...
- 轻松搭建CAS 5.x系列(9)-登录后显示通知信息
概述说明 用户在账号名密码认证通过后,CAS可以跳转到登陆完成页面前,显示相关的通知页面. 搭建步骤 `1. 首先,您需要有个CAS Server端 如果您没有,可以按照我之前写的文章<轻松搭建 ...
- Ionic app 通知在Moto 360 Watch上显示通知(2)
在前一篇文章中,我们已经将Wtach的环境测试成功,下面进入我们自己消息的接收. 1.安装JPush插件在我们的App中,这个具体步骤可以参考 Ionic 安装JPush过程 2.在App上的登录模块 ...
- windows10 中微信(UWP)版本不显示通知消息
前言: 前段时间笔者更换了升级了WINDOWS10系统,从应用商店安装微信后,使用期间不会推送消息通知,右下角的通知栏也无法添加微信图标.搜索百度和Google后,发现很多人都是这样,这是微信(UWP ...
- android 前台服务不显示通知
原因可以在哪里写了执行完成后就自动结束的吧 导致前台服务没有出现 如我 @Override public int onStartCommand(Intent intent, int flags, in ...
随机推荐
- 破解webstorm
补丁下载链接:http://idea.lanyus.com/ 第一步:将补丁复制到安装目录的bin目录下 第二步:修改同目录下的 WebStorm.exe.vmoptions 和WebStorm64. ...
- JMeter使用中遇到的问题:Jmeter Debug - "Unrecognized VM option '+HeapDumpOnOutOfMemoryError"(转载)
转载自 http://www.cnblogs.com/yangxia-test 启动JMeter.bat的程序时,出现以下出错信息: Unrecognized VM option '+HeapDump ...
- CentOS 下搭建Gitlab
centos7安装部署gitlab服务器 我这里使用的是centos 7 64bit,我试过centos 6也是可以的! 1. 安装依赖软件 yum -y install policycoreut ...
- CentOS 7系统根目录分区扩容
说明:系统版本为 Linux version 3.10.0-327.el7.x86_64 1. 查看现有磁盘信息,可以看出根分区有45G [root@DEV-CMDB-DB02 ~]# df -h F ...
- shape 图形
主要属性: <?xml version="1.0"encoding="utf-8"?><shape > <corners /> ...
- UVa 10054 The Necklace(无向图欧拉回路)
My little sister had a beautiful necklace made of colorful beads. Two successive beads in the neckla ...
- f5创建monitor
- shell条件控制和循环结构
一.简介 Shell编程中循环命令用于特定条件下决定某些语句重复执行的控制方式,有三种常用的循环语句:for.while和until.while循环和for循环属于“当型循环”,而until属于“直到 ...
- elastic5.4安装错误解决
首先,我们从官网下载:(官网:https://www.elastic.co/downloads/elasticsearch)(推荐下载deb或者rpm包,否则坑很多) 启动 (需要依赖java环境) ...
- export命令
http://blog.csdn.net/wl_fln/article/details/7258294 http://man.linuxde.net/export export命令 功能说明:设置或显 ...