NotificationMangerService处理显示通知

设置——>应用——>点击“已下载”列表中的任一APP,如图:

 代码位置:Settings\src\com\android\settings\applications\InstalledAppDetails.java

 1 //CheckBox显示通知处理
 2 private void setNotificationsEnabled(boolean enabled) {
 3         String packageName = mAppEntry.info.packageName;
 4         INotificationManager nm = INotificationManager.Stub.asInterface(
 5                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
 6         try {
 7             final boolean enable = mNotificationSwitch.isChecked();
 8
 9             nm.setNotificationsEnabledForPackage(packageName, mAppEntry.info.uid, enabled);
10         } catch (android.os.RemoteException ex) {
11             mNotificationSwitch.setChecked(!enabled); // revert
12         }
13     }
INotificationManager 是通过AIDL处理,在java层就是NotificationMangerService处理。android\frameworks\base\services\java\com\android\server\NotificationManagerService.java
 1 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
 2         checkCallerIsSystem();//这里校验Uid检查调用程序有没有权限
 3
 4         Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
 5
 6         mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
 7                 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
 8
 9         // Now, cancel any outstanding notifications that are part of a just-disabled app
10         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
11             cancelAllNotificationsInt(pkg, 0, 0, true, UserHandle.getUserId(uid));
12         }
13     }
校验Uid检查调用程序有没有权限,了解sharedUserId可以参考http://www.cnblogs.com/Ashia/articles/2474321.html

 1 void checkCallerIsSystem() {
 2         if (isCallerSystem()) {
 3             return;
 4         }
 5         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
 6     }
 7
 8 boolean isCallerSystem() {
 9         return isUidSystem(Binder.getCallingUid());
10     }
11
12 // Return true if the UID is a system or phone UID and therefore should not have
13     // any notifications or toasts blocked.
14     boolean isUidSystem(int uid) {
15         Slog.v(TAG, "isUidSystem , uid = " + uid);
16         final int appid = UserHandle.getAppId(uid);
17         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
18     }

以上处理中mAppOps将需要处理的pkg做了标记,表示是否显示pkg发出的Notification

Notification的显示过程也是NotificationMangerService处理,在enqueueNotificationInternal(......)中处理,这里会判断pkg是否可以显示通知。

  1 // Not exposed via Binder; for system use only (otherwise malicious apps could spoof the
  2     // uid/pid of another application)
  3
  4     public void enqueueNotificationInternal(final String pkg, String basePkg, final int callingUid,
  5             final int callingPid, final String tag, final int id, final Notification notification,
  6             int[] idOut, int incomingUserId)
  7     {
  8         if (DBG) {
  9             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification);
 10         }
 11         checkCallerIsSystemOrSameApp(pkg);
 12         final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));//再次校验Uid
 13
 14         final int userId = ActivityManager.handleIncomingUser(callingPid,
 15                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
 16         final UserHandle user = new UserHandle(userId);
 17
 18         // Limit the number of notifications that any given package except the android
 19         // package can enqueue.  Prevents DOS attacks and deals with leaks.
 20         if (!isSystemNotification) {
 21             synchronized (mNotificationList) {
 22                 int count = 0;
 23                 final int N = mNotificationList.size();
 24                 for (int i=0; i<N; i++) {
 25                     final NotificationRecord r = mNotificationList.get(i);
 26                     if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
 27                         count++;
 28                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {//判断允许的最大通知数
 29                             Slog.e(TAG, "Package has already posted " + count
 30                                     + " notifications.  Not showing more.  package=" + pkg);
 31                             return;
 32                         }
 33                     }
 34                 }
 35             }
 36         }
 37
 38         // This conditional is a dirty hack to limit the logging done on
 39         //     behalf of the download manager without affecting other apps.
 40         if (!pkg.equals("com.android.providers.downloads")
 41                 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
 42             EventLog.writeEvent(EventLogTags.NOTIFICATION_ENQUEUE, pkg, id, tag, userId,
 43                     notification.toString());
 44         }
 45
 46         if (pkg == null || notification == null) {
 47             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
 48                     + " id=" + id + " notification=" + notification);
 49         }
 50         if (notification.icon != 0) {
 51             if (notification.contentView == null) {
 52                 throw new IllegalArgumentException("contentView required: pkg=" + pkg
 53                         + " id=" + id + " notification=" + notification);
 54             }
 55         }
 56
 57         mHandler.post(new Runnable() {
 58             @Override
 59             public void run() {
 60
 61                 // === Scoring ===
 62
 63                 // 0. Sanitize inputs
 64                 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
 65                         Notification.PRIORITY_MAX);
 66                 // Migrate notification flags to scores
 67                 if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
 68                     if (notification.priority < Notification.PRIORITY_MAX) {
 69                         notification.priority = Notification.PRIORITY_MAX;
 70                     }
 71                 } else if (SCORE_ONGOING_HIGHER &&
 72                         0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
 73                     if (notification.priority < Notification.PRIORITY_HIGH) {
 74                         notification.priority = Notification.PRIORITY_HIGH;
 75                     }
 76                 }
 77
 78                 // 1. initial score: buckets of 10, around the app
 79                 int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; //[-20..20]
 80
 81                 // 2. Consult external heuristics (TBD)
 82
 83                 // 3. Apply local rules
 84
 85                 int initialScore = score;
 86                 if (!mScorers.isEmpty()) {
 87                     if (DBG) Slog.v(TAG, "Initial score is " + score + ".");
 88                     for (NotificationScorer scorer : mScorers) {
 89                         try {
 90                             score = scorer.getScore(notification, score);
 91                         } catch (Throwable t) {
 92                             Slog.w(TAG, "Scorer threw on .getScore.", t);
 93                         }
 94                     }
 95                     if (DBG) Slog.v(TAG, "Final score is " + score + ".");
 96                 }
 97
 98                 // add extra to indicate score modified by NotificationScorer
 99                 notification.extras.putBoolean(Notification.EXTRA_SCORE_MODIFIED,
100                         score != initialScore);
101
102                 // blocked apps
103                 if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {//判断pkg是否可以显示通知
104                     if (!isSystemNotification) {//不拦截系统通知
105                         score = JUNK_SCORE; //在设置中禁止显示通知的pkg,会进到这里,JUNK_SCORE=-1000
106                         Slog.e(TAG, "Suppressing notification from package " + pkg
107                                 + " by user request.");
108                     }
109                 }
110
111                 if (DBG) {
112                     Slog.v(TAG, "Assigned score=" + score + " to " + notification);
113                 }
114
115                 if (score < SCORE_DISPLAY_THRESHOLD) {//进行"显示通知"拦截判断,SCORE_DIAPLAY_THRESHOLD=-20
116                     // Notification will be blocked because the score is too low.
117                     return; //完成拦截
118                 }
119
120                 

// 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     }

时间: 2024-10-27 05:14:52

NotificationMangerService处理显示通知的相关文章

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

场景 状态栏上显示通知效果 注: 博客: https://blog.csdn.net/badao_liumang_qizhi关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 新建NotificationActivity,通过getSystemService方法获取通知管理器. 然后创建通知并设置通知的一些属性,再使用通知管理器发送通知. package com.badao.relativelayouttest; import androidx.annotation.Req

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

概述说明 用户在账号名密码认证通过后,CAS可以跳转到登陆完成页面前,显示相关的通知页面. 搭建步骤 `1. 首先,您需要有个CAS Server端 如果您没有,可以按照我之前写的文章<轻松搭建CAS 5.x系列文章>系列的前3篇文章搭建好CAS Server. `2. 在pom.xml增加依赖包 1 <!-- Authentication Interrupt Begin --> 2 <dependency> 3 <groupId>org.apereo.ca

使用Notification在状态栏上显示通知

运行效果图:              结构目录: 注意事项: 如果logcat有错误提示:No Channel found for pkg, 可参考链接:https://blog.csdn.net/u010356768/article/details/83546008 activity_main.xml: 1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:androi

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

在前一篇文章中,我们已经将Wtach的环境测试成功,下面进入我们自己消息的接收. 1.安装JPush插件在我们的App中,这个具体步骤可以参考 Ionic 安装JPush过程 2.在App上的登录模块设置别名,因为我们的目标是,根据不同的账户发送不同的消息. .controller("LoginController",function ($scope, $state, AccountService, $rootScope, $stateParams, $ionicHistory, $i

在程序中点击home键后将程序通知显示到状态栏中

当程序处于后台运作的时候,Activity处于onStop状态,so只要在onStop方法中将程序运行状态显示在状态栏即可 //在状态栏显示程序通知    private void showNotification() {        // 创建一个NotificationManager的引用        NotificationManager notificationManager = (NotificationManager) this                .getSystem

自行扩展 FineUIMvc 通知对话框(多个并排显示不重叠,支持最新的显示在最上方)

声明:FineUIMvc(基础版)是免费软件,本系列文章适用于基础版. 这篇文章我们将改造 FineUIMvc 默认的通知对话框,使得同时显示多个也不会重叠.并提前出一个公共的JS文件,供大家使用. FineUIMvc 的通知对话框 FineUIMvc默认的通知对话框通过 F.notify 来显示,可以在页面上的 9 个位置显示,分别对应于属性: PosotionX = Left,  PositionY = Top PosotionX = Left,  PositionY = Center Po

Android 8.0+ 通知不显示的适配

最近在 写项目的时候  发现 通知并不会显示的问题,查看资料发现 从Android 8.0开始通知必须加上ChannelId Android O 引入了 通知渠道(Notification Channels),以提供统一的系统来帮助用户管理通知,如果是针对 android O 为目标平台时,必须实现一个或者多个通知渠道,以向用户显示通知.比如聊天软件,为每个聊天组设置一个通知渠道,指定特定声音.灯光等配置 String id = "my_id"; String name="m

自定义通知Notification:自己定义通知Notification下拉后的显示样式

注意:以下有些方法需要在build.gradle里修改minSdkVersion 21才能使用 只需在构建普通Notification的构建器builder上添加对bigContentView属性设置为RemoteView(自定义的通知样式),如需要对通知展开视图RemoteView里的UI控件设置监听,需要通过设置广播和RemoteView的setOnClickPendingIntent()方法配合使用 Notification notification; NotificationManage

通知栏Notification在不同手机上显示的问题总结

可以参照http://blog.csdn.net/vipzjyno1/article/details/25248021,这里面关于通知的写的不错,也很全面,我的这篇主要是记录自己在适配上遇到的问题. 通知的统一的创建方式: NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext); 而通知的管理则是使用NotificationManager是用来管理通知的,使用如下:先初始化用到的系统服务,然后调