设置——>应用——>点击“已下载”列表中的任一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处理显示通知的更多相关文章

  1. PendingIntent 显示通知

    安卓显示通知 PendingIntent pendingIntent=PendingIntent.getActivity(Media.this,0, new Intent(Media.this,Med ...

  2. Android中使用Notification在状态栏上显示通知

    场景 状态栏上显示通知效果 注: 博客: https://blog.csdn.net/badao_liumang_qizhi关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新 ...

  3. Android学习笔记使用Notication 显示通知

    实现步骤 代码实现 创建MainActivity和DetailActivity(点击通知后要跳转的Activity),两个Activity的布局文件就是添加一张全屏的背景图,老规矩,不粘贴. Main ...

  4. Android开发之显示通知

    Toast类可以用来显示消息给用户,虽然它很方便,但是有不能持久.它只是在屏幕上显示几秒后就自动消失掉了.对于重要的信息或消息,要使用更加持久的方法.这种情形下,就应当使用通知,即使用Notifica ...

  5. Ionic app 通知在Moto 360 Watch上显示通知(1)

    手机与Moto 360 watch配对之后,watch上会接收到微信消息的通知,那么我们就可以利用这个特性开发一个App,在Watch显示我们自己的通知,具体过程如下 1.手机扫描二维码安装ticwa ...

  6. 轻松搭建CAS 5.x系列(9)-登录后显示通知信息

    概述说明 用户在账号名密码认证通过后,CAS可以跳转到登陆完成页面前,显示相关的通知页面. 搭建步骤 `1. 首先,您需要有个CAS Server端 如果您没有,可以按照我之前写的文章<轻松搭建 ...

  7. Ionic app 通知在Moto 360 Watch上显示通知(2)

    在前一篇文章中,我们已经将Wtach的环境测试成功,下面进入我们自己消息的接收. 1.安装JPush插件在我们的App中,这个具体步骤可以参考 Ionic 安装JPush过程 2.在App上的登录模块 ...

  8. windows10 中微信(UWP)版本不显示通知消息

    前言: 前段时间笔者更换了升级了WINDOWS10系统,从应用商店安装微信后,使用期间不会推送消息通知,右下角的通知栏也无法添加微信图标.搜索百度和Google后,发现很多人都是这样,这是微信(UWP ...

  9. android 前台服务不显示通知

    原因可以在哪里写了执行完成后就自动结束的吧 导致前台服务没有出现 如我 @Override public int onStartCommand(Intent intent, int flags, in ...

随机推荐

  1. 在window下搭建Vue.Js开发环境(转)

    nodejs官网http://nodejs.cn/下载安装包,无特殊要求可本地傻瓜式安装,这里选择2017-5-2发布的 v6.10.3 cmd命令行: node -v //显示node版本 v6.1 ...

  2. Oracle怎么修改字段类型

    转载:https://www.2cto.com/database/201710/689523.html 有一个表名为tb,字段段名为name,数据类型nchar(20). 1.假设字段数据为空,则不管 ...

  3. STL::unordered_map/unordered_multimap

    unordered_map: 和 unorder_set 相似,该容器内部同样根据 hash value 把键值对存放到相应的 bucket(slot)中,根据单个 key 来访问 value 的速度 ...

  4. PAT1131(dfs)

    In the big cities, the subway systems always look so complex to the visitors. To give you some sense ...

  5. Monkey 命令收集相关 --追加Monkey自动化测试开源工具

    .1.环境配置 MONKEY测试使用的是ADB命令,因此只需要配置ADB环境即可. 2.测试准备与执行 在Monkey测试前,必须进行以下准备 Ø  手机屏幕超时设置为30分钟或者永不超时,防止手机进 ...

  6. RxJS之组合操作符 ( Angular环境 )

    一 merge操作符 把多个 Observables 的值混合到一个 Observable 中 import { Component, OnInit } from '@angular/core'; i ...

  7. 公告栏添加时钟——利用canvas画出一个时钟

    前言 最近在学习HTML5标签,学到Canvas,觉得很有趣.便在慕课网找了个demo练手.就是Canvas时钟. 对于canvas,w3shcool上是这么描述的: HTML5 <canvas ...

  8. EOJ Monthly 2018.7 B.锐角三角形(数学几何+思维)

    描述 是否存在面积为S/2的整点锐角三角形?存在输出Yes并输出三个整点坐标,否则输出No. 注意如果存在输出的坐标必须在long long范围内. Input 第一行一个整数S(1<=S< ...

  9. PTA 7-6 列出连通集(深搜+广搜)

    给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集.假设顶点从0到N−1编号.进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点. 输入格式: 输入第1 ...

  10. iOS 编译部署路径

    <转> 在 OSX 上初次接触到这些变量,  做一个总结.在编译一个动态库比如 libfoo.dylib 的时候, 你需要指定 INSTALL_PATH. 也就是它的安装路径.一个可执行程 ...