OSDN Git Service

a15d7b1548709ba3d4aab495faf1659ee045cc29
[android-x86/frameworks-base.git] / services / core / java / com / android / server / notification / NotificationManagerService.java
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  * Copyright (C) 2015 The CyanogenMod Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package com.android.server.notification;
19
20 import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
21 import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
22 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
23 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
24 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
25 import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
26 import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
27 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
28 import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
29 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
30 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
31 import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
32 import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
33 import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
34 import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
35 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
36 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
37 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
38 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
39 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
40 import static android.service.notification.NotificationListenerService.TRIM_FULL;
41 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
42 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
43 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
44
45 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
46
47 import android.Manifest;
48 import android.annotation.Nullable;
49 import android.app.ActivityManager;
50 import android.app.ActivityManagerInternal;
51 import android.app.ActivityManagerNative;
52 import android.app.AppGlobals;
53 import android.app.AppOpsManager;
54 import android.app.AutomaticZenRule;
55 import android.app.IActivityManager;
56 import android.app.INotificationManager;
57 import android.app.ITransientNotification;
58 import android.app.KeyguardManager;
59 import android.app.Notification;
60 import android.app.NotificationManager;
61 import android.app.NotificationManager.Policy;
62 import android.app.PendingIntent;
63 import android.app.RemoteInput;
64 import android.app.StatusBarManager;
65 import android.app.backup.BackupManager;
66 import android.app.usage.UsageEvents;
67 import android.app.usage.UsageStatsManagerInternal;
68 import android.content.BroadcastReceiver;
69 import android.content.ComponentName;
70 import android.content.ContentResolver;
71 import android.content.Context;
72 import android.content.Intent;
73 import android.content.IntentFilter;
74 import android.content.pm.ApplicationInfo;
75 import android.content.pm.IPackageManager;
76 import android.content.pm.PackageInfo;
77 import android.content.pm.PackageManager;
78 import android.content.pm.PackageManager.NameNotFoundException;
79 import android.content.pm.ParceledListSlice;
80 import android.content.pm.UserInfo;
81 import android.content.res.Resources;
82 import android.database.ContentObserver;
83 import android.graphics.drawable.Drawable;
84 import android.media.AudioAttributes;
85 import android.media.AudioManager;
86 import android.media.AudioManagerInternal;
87 import android.media.AudioSystem;
88 import android.media.IRingtonePlayer;
89 import android.net.Uri;
90 import android.os.Binder;
91 import android.os.Bundle;
92 import android.os.Environment;
93 import android.os.Handler;
94 import android.os.HandlerThread;
95 import android.os.IBinder;
96 import android.os.IInterface;
97 import android.os.Looper;
98 import android.os.Message;
99 import android.os.Parcelable;
100 import android.os.PersistableBundle;
101 import android.os.Process;
102 import android.os.RemoteException;
103 import android.os.SystemClock;
104 import android.os.SystemProperties;
105 import android.os.UserHandle;
106 import android.os.UserManager;
107 import android.os.Vibrator;
108 import android.provider.Settings;
109 import android.service.notification.Adjustment;
110 import android.service.notification.Condition;
111 import android.service.notification.IConditionProvider;
112 import android.service.notification.INotificationListener;
113 import android.service.notification.IStatusBarNotificationHolder;
114 import android.service.notification.NotificationRankerService;
115 import android.service.notification.NotificationListenerService;
116 import android.service.notification.NotificationRankingUpdate;
117 import android.service.notification.StatusBarNotification;
118 import android.service.notification.ZenModeConfig;
119 import android.telephony.CarrierConfigManager;
120 import android.telephony.PhoneStateListener;
121 import android.telephony.TelephonyManager;
122 import android.text.TextUtils;
123 import android.util.ArrayMap;
124 import android.util.ArraySet;
125 import android.util.AtomicFile;
126 import android.util.Log;
127 import android.util.Slog;
128 import android.util.SparseArray;
129 import android.util.Xml;
130 import android.view.accessibility.AccessibilityEvent;
131 import android.view.accessibility.AccessibilityManager;
132 import android.widget.Toast;
133
134 import com.android.internal.R;
135 import com.android.internal.annotations.VisibleForTesting;
136 import com.android.internal.statusbar.NotificationVisibility;
137 import com.android.internal.util.FastXmlSerializer;
138 import com.android.internal.util.Preconditions;
139 import com.android.server.DeviceIdleController;
140 import com.android.server.EventLogTags;
141 import com.android.server.LocalServices;
142 import com.android.server.SystemService;
143 import com.android.server.lights.Light;
144 import com.android.server.lights.LightsManager;
145 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
146 import com.android.server.statusbar.StatusBarManagerInternal;
147 import com.android.server.vr.VrManagerInternal;
148 import com.android.server.notification.ManagedServices.UserProfiles;
149
150 import cyanogenmod.providers.CMSettings;
151 import cyanogenmod.util.ColorUtils;
152
153 import cyanogenmod.providers.CMSettings;
154 import libcore.io.IoUtils;
155
156 import org.json.JSONException;
157 import org.json.JSONObject;
158 import org.xmlpull.v1.XmlPullParser;
159 import org.xmlpull.v1.XmlPullParserException;
160 import org.xmlpull.v1.XmlSerializer;
161
162 import java.io.ByteArrayInputStream;
163 import java.io.ByteArrayOutputStream;
164 import java.io.File;
165 import java.io.FileDescriptor;
166 import java.io.FileInputStream;
167 import java.io.FileNotFoundException;
168 import java.io.FileOutputStream;
169 import java.io.IOException;
170 import java.io.InputStream;
171 import java.io.OutputStream;
172 import java.io.PrintWriter;
173 import java.nio.charset.StandardCharsets;
174 import java.util.ArrayDeque;
175 import java.util.ArrayList;
176 import java.util.Arrays;
177 import java.util.Iterator;
178 import java.util.List;
179 import java.util.Map;
180 import java.util.Map.Entry;
181 import java.util.Set;
182 import java.util.concurrent.TimeUnit;
183
184 /** {@hide} */
185 public class NotificationManagerService extends SystemService {
186     static final String TAG = "NotificationService";
187     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
188     public static final boolean ENABLE_CHILD_NOTIFICATIONS
189             = SystemProperties.getBoolean("debug.child_notifs", true);
190
191     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
192     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 50f;
193
194     // message codes
195     static final int MESSAGE_TIMEOUT = 2;
196     static final int MESSAGE_SAVE_POLICY_FILE = 3;
197     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
198     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
199     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
200
201     // ranking thread messages
202     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
203     private static final int MESSAGE_RANKING_SORT = 1001;
204
205     static final int LONG_DELAY = 3500; // 3.5 seconds
206     static final int SHORT_DELAY = 2000; // 2 seconds
207
208     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
209
210     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
211
212     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
213
214     static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
215     static final boolean ENABLE_BLOCKED_TOASTS = true;
216
217     // When #matchesCallFilter is called from the ringer, wait at most
218     // 3s to resolve the contacts. This timeout is required since
219     // ContactsProvider might take a long time to start up.
220     //
221     // Return STARRED_CONTACT when the timeout is hit in order to avoid
222     // missed calls in ZEN mode "Important".
223     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
224     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
225             ValidateNotificationPeople.STARRED_CONTACT;
226
227     /** notification_enqueue status value for a newly enqueued notification. */
228     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
229
230     /** notification_enqueue status value for an existing notification. */
231     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
232
233     /** notification_enqueue status value for an ignored notification. */
234     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
235     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
236     private String mRankerServicePackageName;
237
238     /** notification light maximum brightness value to use. */
239     private static final int LIGHT_BRIGHTNESS_MAXIMUM = 255;
240
241     private IActivityManager mAm;
242     AudioManager mAudioManager;
243     AudioManagerInternal mAudioManagerInternal;
244     @Nullable StatusBarManagerInternal mStatusBar;
245     Vibrator mVibrator;
246     private VrManagerInternal mVrManagerInternal;
247
248     final IBinder mForegroundToken = new Binder();
249     private Handler mHandler;
250     private final HandlerThread mRankingThread = new HandlerThread("ranker",
251             Process.THREAD_PRIORITY_BACKGROUND);
252
253     private Light mNotificationLight;
254     Light mAttentionLight;
255     private int mDefaultNotificationColor;
256     private int mDefaultNotificationLedOn;
257
258     private int mDefaultNotificationLedOff;
259     private long[] mDefaultVibrationPattern;
260
261     private boolean mAdjustableNotificationLedBrightness;
262     private int mNotificationLedBrightnessLevel = LIGHT_BRIGHTNESS_MAXIMUM;
263
264     private boolean mMultipleNotificationLeds;
265     private boolean mMultipleLedsEnabledSetting = false;
266
267     private boolean mAutoGenerateNotificationColor = true;
268
269     private boolean mScreenOnEnabled = false;
270     private boolean mScreenOnDefault = false;
271
272     private long[] mFallbackVibrationPattern;
273     private boolean mUseAttentionLight;
274     boolean mSystemReady;
275
276     private boolean mDisableNotificationEffects;
277     private int mCallState;
278     private String mSoundNotificationKey;
279     private String mVibrateNotificationKey;
280
281     private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
282             new SparseArray<ArraySet<ManagedServiceInfo>>();
283     private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
284     private int mListenerHints;  // right now, all hints are global
285     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
286
287     // for enabling and disabling notification pulse behavior
288     private boolean mScreenOn = true;
289     private boolean mInCall = false;
290     private boolean mNotificationPulseEnabled;
291     private ArrayMap<String, NotificationLedValues> mNotificationPulseCustomLedValues;
292     private Map<String, String> mPackageNameMappings;
293     private final ArrayMap<String, Integer> mGeneratedPackageLedColors =
294         new ArrayMap<String, Integer>();
295
296     // for checking lockscreen status
297     private KeyguardManager mKeyguardManager;
298
299     // used as a mutex for access to all active notifications & listeners
300     final ArrayList<NotificationRecord> mNotificationList =
301             new ArrayList<NotificationRecord>();
302     final ArrayMap<String, NotificationRecord> mNotificationsByKey =
303             new ArrayMap<String, NotificationRecord>();
304     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
305     final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
306     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
307     final PolicyAccess mPolicyAccess = new PolicyAccess();
308
309     // The last key in this list owns the hardware.
310     ArrayList<String> mLights = new ArrayList<>();
311
312     private AppOpsManager mAppOps;
313     private UsageStatsManagerInternal mAppUsageStats;
314
315     private Archive mArchive;
316
317     // Persistent storage for notification policy
318     private AtomicFile mPolicyFile;
319
320     private static final int DB_VERSION = 1;
321
322     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
323     private static final String ATTR_VERSION = "version";
324
325     private RankingHelper mRankingHelper;
326
327     private final UserProfiles mUserProfiles = new UserProfiles();
328     private NotificationListeners mListeners;
329     private NotificationRankers mRankerServices;
330     private ConditionProviders mConditionProviders;
331     private NotificationUsageStats mUsageStats;
332
333     private boolean mMultiColorNotificationLed;
334
335     private static final int MY_UID = Process.myUid();
336     private static final int MY_PID = Process.myPid();
337     private RankingHandler mRankingHandler;
338     private long mLastOverRateLogTime;
339     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
340     private PersistableBundle mCarrierConfig;
341     private CarrierConfigManager mConfigManager;
342
343     private static class Archive {
344         final int mBufferSize;
345         final ArrayDeque<StatusBarNotification> mBuffer;
346
347         public Archive(int size) {
348             mBufferSize = size;
349             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
350         }
351
352         public String toString() {
353             final StringBuilder sb = new StringBuilder();
354             final int N = mBuffer.size();
355             sb.append("Archive (");
356             sb.append(N);
357             sb.append(" notification");
358             sb.append((N==1)?")":"s)");
359             return sb.toString();
360         }
361
362         public void record(StatusBarNotification nr) {
363             if (mBuffer.size() == mBufferSize) {
364                 mBuffer.removeFirst();
365             }
366
367             // We don't want to store the heavy bits of the notification in the archive,
368             // but other clients in the system process might be using the object, so we
369             // store a (lightened) copy.
370             mBuffer.addLast(nr.cloneLight());
371         }
372
373         public Iterator<StatusBarNotification> descendingIterator() {
374             return mBuffer.descendingIterator();
375         }
376
377         public StatusBarNotification[] getArray(int count) {
378             if (count == 0) count = mBufferSize;
379             final StatusBarNotification[] a
380                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
381             Iterator<StatusBarNotification> iter = descendingIterator();
382             int i=0;
383             while (iter.hasNext() && i < count) {
384                 a[i++] = iter.next();
385             }
386             return a;
387         }
388
389     }
390
391     private void readPolicyXml(InputStream stream, boolean forRestore)
392             throws XmlPullParserException, NumberFormatException, IOException {
393         final XmlPullParser parser = Xml.newPullParser();
394         parser.setInput(stream, StandardCharsets.UTF_8.name());
395
396         while (parser.next() != END_DOCUMENT) {
397             mZenModeHelper.readXml(parser, forRestore);
398             mRankingHelper.readXml(parser, forRestore);
399         }
400     }
401
402     private void loadPolicyFile() {
403         if (DBG) Slog.d(TAG, "loadPolicyFile");
404         synchronized(mPolicyFile) {
405
406             FileInputStream infile = null;
407             try {
408                 infile = mPolicyFile.openRead();
409                 readPolicyXml(infile, false /*forRestore*/);
410             } catch (FileNotFoundException e) {
411                 // No data yet
412             } catch (IOException e) {
413                 Log.wtf(TAG, "Unable to read notification policy", e);
414             } catch (NumberFormatException e) {
415                 Log.wtf(TAG, "Unable to parse notification policy", e);
416             } catch (XmlPullParserException e) {
417                 Log.wtf(TAG, "Unable to parse notification policy", e);
418             } finally {
419                 IoUtils.closeQuietly(infile);
420             }
421         }
422     }
423
424     public void savePolicyFile() {
425         mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
426         mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
427     }
428
429     private void handleSavePolicyFile() {
430         if (DBG) Slog.d(TAG, "handleSavePolicyFile");
431         synchronized (mPolicyFile) {
432             final FileOutputStream stream;
433             try {
434                 stream = mPolicyFile.startWrite();
435             } catch (IOException e) {
436                 Slog.w(TAG, "Failed to save policy file", e);
437                 return;
438             }
439
440             try {
441                 writePolicyXml(stream, false /*forBackup*/);
442                 mPolicyFile.finishWrite(stream);
443             } catch (IOException e) {
444                 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
445                 mPolicyFile.failWrite(stream);
446             }
447         }
448         BackupManager.dataChanged(getContext().getPackageName());
449     }
450
451     private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
452         final XmlSerializer out = new FastXmlSerializer();
453         out.setOutput(stream, StandardCharsets.UTF_8.name());
454         out.startDocument(null, true);
455         out.startTag(null, TAG_NOTIFICATION_POLICY);
456         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
457         mZenModeHelper.writeXml(out, forBackup);
458         mRankingHelper.writeXml(out, forBackup);
459         out.endTag(null, TAG_NOTIFICATION_POLICY);
460         out.endDocument();
461     }
462
463     /** Use this when you actually want to post a notification or toast.
464      *
465      * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
466      */
467     private boolean noteNotificationOp(String pkg, int uid) {
468         if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
469                 != AppOpsManager.MODE_ALLOWED) {
470             Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
471             return false;
472         }
473         return true;
474     }
475
476     /** Use this to check if a package can post a notification or toast. */
477     private boolean checkNotificationOp(String pkg, int uid) {
478         return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
479                 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
480     }
481
482     private static final class ToastRecord
483     {
484         final int pid;
485         final String pkg;
486         final ITransientNotification callback;
487         int duration;
488
489         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
490         {
491             this.pid = pid;
492             this.pkg = pkg;
493             this.callback = callback;
494             this.duration = duration;
495         }
496
497         void update(int duration) {
498             this.duration = duration;
499         }
500
501         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
502             if (filter != null && !filter.matches(pkg)) return;
503             pw.println(prefix + this);
504         }
505
506         @Override
507         public final String toString()
508         {
509             return "ToastRecord{"
510                 + Integer.toHexString(System.identityHashCode(this))
511                 + " pkg=" + pkg
512                 + " callback=" + callback
513                 + " duration=" + duration;
514         }
515     }
516
517     class NotificationLedValues {
518         public int color;
519         public int onMS;
520         public int offMS;
521     }
522
523     private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
524
525         @Override
526         public void onSetDisabled(int status) {
527             synchronized (mNotificationList) {
528                 mDisableNotificationEffects =
529                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
530                 if (disableNotificationEffects(null) != null) {
531                     // cancel whatever's going on
532                     long identity = Binder.clearCallingIdentity();
533                     try {
534                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
535                         if (player != null) {
536                             player.stopAsync();
537                         }
538                     } catch (RemoteException e) {
539                     } finally {
540                         Binder.restoreCallingIdentity(identity);
541                     }
542
543                     identity = Binder.clearCallingIdentity();
544                     try {
545                         mVibrator.cancel();
546                     } finally {
547                         Binder.restoreCallingIdentity(identity);
548                     }
549                 }
550             }
551         }
552
553         @Override
554         public void onClearAll(int callingUid, int callingPid, int userId) {
555             synchronized (mNotificationList) {
556                 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
557                         /*includeCurrentProfiles*/ true);
558             }
559         }
560
561         @Override
562         public void onNotificationClick(int callingUid, int callingPid, String key) {
563             synchronized (mNotificationList) {
564                 NotificationRecord r = mNotificationsByKey.get(key);
565                 if (r == null) {
566                     Log.w(TAG, "No notification with key: " + key);
567                     return;
568                 }
569                 final long now = System.currentTimeMillis();
570                 EventLogTags.writeNotificationClicked(key,
571                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
572
573                 StatusBarNotification sbn = r.sbn;
574                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
575                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
576                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
577                         REASON_DELEGATE_CLICK, null);
578             }
579         }
580
581         @Override
582         public void onNotificationActionClick(int callingUid, int callingPid, String key,
583                 int actionIndex) {
584             synchronized (mNotificationList) {
585                 NotificationRecord r = mNotificationsByKey.get(key);
586                 if (r == null) {
587                     Log.w(TAG, "No notification with key: " + key);
588                     return;
589                 }
590                 final long now = System.currentTimeMillis();
591                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
592                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
593                 // TODO: Log action click via UsageStats.
594             }
595         }
596
597         @Override
598         public void onNotificationClear(int callingUid, int callingPid,
599                 String pkg, String tag, int id, int userId) {
600             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
601                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
602                     true, userId, REASON_DELEGATE_CANCEL, null);
603         }
604
605         @Override
606         public void onPanelRevealed(boolean clearEffects, int items) {
607             EventLogTags.writeNotificationPanelRevealed(items);
608             if (clearEffects) {
609                 clearEffects();
610             }
611         }
612
613         @Override
614         public void onPanelHidden() {
615             EventLogTags.writeNotificationPanelHidden();
616         }
617
618         @Override
619         public void clearEffects() {
620             synchronized (mNotificationList) {
621                 if (DBG) Slog.d(TAG, "clearEffects");
622                 clearSoundLocked();
623                 clearVibrateLocked();
624                 clearLightsLocked();
625             }
626         }
627
628         @Override
629         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
630                 int uid, int initialPid, String message, int userId) {
631             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
632                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
633             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
634                     REASON_DELEGATE_ERROR, null);
635             long ident = Binder.clearCallingIdentity();
636             try {
637                 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
638                         "Bad notification posted from package " + pkg
639                         + ": " + message);
640             } catch (RemoteException e) {
641             } finally {
642                 Binder.restoreCallingIdentity(ident);
643             }
644         }
645
646         @Override
647         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
648                 NotificationVisibility[] noLongerVisibleKeys) {
649             synchronized (mNotificationList) {
650                 for (NotificationVisibility nv : newlyVisibleKeys) {
651                     NotificationRecord r = mNotificationsByKey.get(nv.key);
652                     if (r == null) continue;
653                     r.setVisibility(true, nv.rank);
654                     nv.recycle();
655                 }
656                 // Note that we might receive this event after notifications
657                 // have already left the system, e.g. after dismissing from the
658                 // shade. Hence not finding notifications in
659                 // mNotificationsByKey is not an exceptional condition.
660                 for (NotificationVisibility nv : noLongerVisibleKeys) {
661                     NotificationRecord r = mNotificationsByKey.get(nv.key);
662                     if (r == null) continue;
663                     r.setVisibility(false, nv.rank);
664                     nv.recycle();
665                 }
666             }
667         }
668
669         @Override
670         public void onNotificationExpansionChanged(String key,
671                 boolean userAction, boolean expanded) {
672             synchronized (mNotificationList) {
673                 NotificationRecord r = mNotificationsByKey.get(key);
674                 if (r != null) {
675                     r.stats.onExpansionChanged(userAction, expanded);
676                     final long now = System.currentTimeMillis();
677                     EventLogTags.writeNotificationExpansion(key,
678                             userAction ? 1 : 0, expanded ? 1 : 0,
679                             r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
680                 }
681             }
682         }
683     };
684
685     private void clearSoundLocked() {
686         mSoundNotificationKey = null;
687         long identity = Binder.clearCallingIdentity();
688         try {
689             final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
690             if (player != null) {
691                 player.stopAsync();
692             }
693         } catch (RemoteException e) {
694         } finally {
695             Binder.restoreCallingIdentity(identity);
696         }
697     }
698
699     private void clearVibrateLocked() {
700         mVibrateNotificationKey = null;
701         long identity = Binder.clearCallingIdentity();
702         try {
703             mVibrator.cancel();
704         } finally {
705             Binder.restoreCallingIdentity(identity);
706         }
707     }
708
709     private void clearLightsLocked() {
710         // lights
711                 // clear only if lockscreen is not active
712                 if (mKeyguardManager != null && !mKeyguardManager.isKeyguardLocked()) {
713                         mLights.clear();
714                         updateLightsLocked();
715                 }
716     }
717
718     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
719         @Override
720         public void onReceive(Context context, Intent intent) {
721             String action = intent.getAction();
722             if (action == null) {
723                 return;
724             }
725
726             boolean queryRestart = false;
727             boolean queryRemove = false;
728             boolean packageChanged = false;
729             boolean cancelNotifications = true;
730             int reason = REASON_PACKAGE_CHANGED;
731
732             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
733                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
734                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
735                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
736                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
737                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
738                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
739                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
740                         UserHandle.USER_ALL);
741                 String pkgList[] = null;
742                 boolean queryReplace = queryRemove &&
743                         intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
744                 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
745                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
746                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
747                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
748                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
749                     reason = REASON_PACKAGE_SUSPENDED;
750                 } else if (queryRestart) {
751                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
752                 } else {
753                     Uri uri = intent.getData();
754                     if (uri == null) {
755                         return;
756                     }
757                     String pkgName = uri.getSchemeSpecificPart();
758                     if (pkgName == null) {
759                         return;
760                     }
761                     if (packageChanged) {
762                         // We cancel notifications for packages which have just been disabled
763                         try {
764                             final IPackageManager pm = AppGlobals.getPackageManager();
765                             final int enabled = pm.getApplicationEnabledSetting(pkgName,
766                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
767                                     UserHandle.USER_SYSTEM);
768                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
769                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
770                                 cancelNotifications = false;
771                             }
772                         } catch (IllegalArgumentException e) {
773                             // Package doesn't exist; probably racing with uninstall.
774                             // cancelNotifications is already true, so nothing to do here.
775                             if (DBG) {
776                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
777                             }
778                         } catch (RemoteException e) {
779                             // Failed to talk to PackageManagerService Should never happen!
780                         }
781                     }
782                     pkgList = new String[]{pkgName};
783                 }
784
785                 if (pkgList != null && (pkgList.length > 0)) {
786                     for (String pkgName : pkgList) {
787                         if (cancelNotifications) {
788                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
789                                     changeUserId, reason, null);
790                         }
791                     }
792                 }
793                 mListeners.onPackagesChanged(queryReplace, pkgList);
794                 mRankerServices.onPackagesChanged(queryReplace, pkgList);
795                 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
796                 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
797             }
798         }
799     };
800
801     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
802         @Override
803         public void onReceive(Context context, Intent intent) {
804             String action = intent.getAction();
805
806             if (action.equals(Intent.ACTION_SCREEN_ON)) {
807                 // Keep track of screen on/off state, but do not turn off the notification light
808                 // until user passes through the lock screen or views the notification.
809                 mScreenOn = true;
810                 updateNotificationPulse();
811             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
812                 mScreenOn = false;
813                 updateNotificationPulse();
814             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
815                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
816                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
817                 updateNotificationPulse();
818             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
819                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
820                 if (userHandle >= 0) {
821                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
822                             REASON_USER_STOPPED, null);
823                 }
824             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
825                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
826                 if (userHandle >= 0) {
827                     cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
828                             REASON_PROFILE_TURNED_OFF, null);
829                 }
830             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
831                 // turn off LED when user passes through lock screen
832                 // if lights with screen on is disabled.
833                 if (!mScreenOnEnabled) {
834                     mNotificationLight.turnOff();
835
836                     if (mStatusBar != null) {
837                         mStatusBar.notificationLightOff();
838                     }
839                 }
840             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
841                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
842                 // reload per-user settings
843                 mSettingsObserver.update(null);
844                 mUserProfiles.updateCache(context);
845                 // Refresh managed services
846                 mConditionProviders.onUserSwitched(user);
847                 mListeners.onUserSwitched(user);
848                 mRankerServices.onUserSwitched(user);
849                 mZenModeHelper.onUserSwitched(user);
850             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
851                 mUserProfiles.updateCache(context);
852             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
853                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
854                 mZenModeHelper.onUserRemoved(user);
855             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
856                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
857                 mConditionProviders.onUserUnlocked(user);
858                 mListeners.onUserUnlocked(user);
859                 mRankerServices.onUserUnlocked(user);
860                 mZenModeHelper.onUserUnlocked(user);
861             }
862         }
863     };
864
865     private final class LEDSettingsObserver extends ContentObserver {
866         private final Uri NOTIFICATION_LIGHT_PULSE_URI
867                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
868         private final Uri NOTIFICATION_RATE_LIMIT_URI
869                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
870         private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
871                 = Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
872
873         LEDSettingsObserver(Handler handler) {
874             super(handler);
875         }
876
877         void observe() {
878             ContentResolver resolver = getContext().getContentResolver();
879             resolver.registerContentObserver(
880                     NOTIFICATION_LIGHT_PULSE_URI, false, this, UserHandle.USER_ALL);
881             resolver.registerContentObserver(
882                     ENABLED_NOTIFICATION_LISTENERS_URI, false, this, UserHandle.USER_ALL);
883             resolver.registerContentObserver(CMSettings.System.getUriFor(
884                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR),
885                     false, this, UserHandle.USER_ALL);
886             resolver.registerContentObserver(CMSettings.System.getUriFor(
887                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON),
888                     false, this, UserHandle.USER_ALL);
889             resolver.registerContentObserver(CMSettings.System.getUriFor(
890                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF),
891                     false, this, UserHandle.USER_ALL);
892             resolver.registerContentObserver(CMSettings.System.getUriFor(
893                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE),
894                     false, this, UserHandle.USER_ALL);
895             resolver.registerContentObserver(CMSettings.System.getUriFor(
896                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES),
897                     false, this, UserHandle.USER_ALL);
898             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
899                     false, this, UserHandle.USER_ALL);
900             resolver.registerContentObserver(CMSettings.System.getUriFor(
901                     CMSettings.System.NOTIFICATION_LIGHT_SCREEN_ON),
902                     false, this, UserHandle.USER_ALL);
903             resolver.registerContentObserver(CMSettings.System.getUriFor(
904                     CMSettings.System.NOTIFICATION_LIGHT_COLOR_AUTO), false,
905                     this, UserHandle.USER_ALL);
906             if (mAdjustableNotificationLedBrightness) {
907                 resolver.registerContentObserver(CMSettings.System.getUriFor(
908                         CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL),
909                         false, this, UserHandle.USER_ALL);
910             }
911             if (mMultipleNotificationLeds) {
912                 resolver.registerContentObserver(CMSettings.System.getUriFor(
913                         CMSettings.System.NOTIFICATION_LIGHT_MULTIPLE_LEDS_ENABLE),
914                         false, this, UserHandle.USER_ALL);
915             }
916             update(null);
917         }
918
919         @Override public void onChange(boolean selfChange, Uri uri) {
920             update(uri);
921         }
922
923         public void update(Uri uri) {
924             ContentResolver resolver = getContext().getContentResolver();
925
926             // LED enabled
927             mNotificationPulseEnabled = Settings.System.getIntForUser(resolver,
928                     Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
929
930             // Automatically pick a color for LED if not set
931             mAutoGenerateNotificationColor = CMSettings.System.getIntForUser(resolver,
932                     CMSettings.System.NOTIFICATION_LIGHT_COLOR_AUTO,
933                     1, UserHandle.USER_CURRENT) != 0;
934
935             // LED default color
936             mDefaultNotificationColor = CMSettings.System.getIntForUser(resolver,
937                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR,
938                     mDefaultNotificationColor, UserHandle.USER_CURRENT);
939
940             // LED default on MS
941             mDefaultNotificationLedOn = CMSettings.System.getIntForUser(resolver,
942                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON,
943                     mDefaultNotificationLedOn, UserHandle.USER_CURRENT);
944
945             // LED default off MS
946             mDefaultNotificationLedOff = CMSettings.System.getIntForUser(resolver,
947                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF,
948                     mDefaultNotificationLedOff, UserHandle.USER_CURRENT);
949
950             // LED generated notification colors
951             mGeneratedPackageLedColors.clear();
952
953             // LED custom notification colors
954             mNotificationPulseCustomLedValues.clear();
955             if (CMSettings.System.getIntForUser(resolver,
956                     CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE, 0,
957                     UserHandle.USER_CURRENT) != 0) {
958                 parseNotificationPulseCustomValuesString(CMSettings.System.getStringForUser(resolver,
959                         CMSettings.System.NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES,
960                         UserHandle.USER_CURRENT));
961             }
962             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
963                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
964                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
965             }
966
967             // Notification LED brightness
968             if (mAdjustableNotificationLedBrightness) {
969                 mNotificationLedBrightnessLevel = CMSettings.System.getIntForUser(resolver,
970                         CMSettings.System.NOTIFICATION_LIGHT_BRIGHTNESS_LEVEL,
971                         LIGHT_BRIGHTNESS_MAXIMUM, UserHandle.USER_CURRENT);
972             }
973
974             // Multiple LEDs enabled
975             if (mMultipleNotificationLeds) {
976                 mMultipleLedsEnabledSetting = (CMSettings.System.getIntForUser(resolver,
977                         CMSettings.System.NOTIFICATION_LIGHT_MULTIPLE_LEDS_ENABLE,
978                         mMultipleNotificationLeds ? 1 : 0, UserHandle.USER_CURRENT) != 0);
979             }
980
981             // Notification lights with screen on
982             mScreenOnEnabled = (CMSettings.System.getIntForUser(resolver,
983                     CMSettings.System.NOTIFICATION_LIGHT_SCREEN_ON,
984                     mScreenOnDefault ? 1 : 0, UserHandle.USER_CURRENT) != 0);
985
986             updateNotificationPulse();
987         }
988     }
989
990     private LEDSettingsObserver mSettingsObserver;
991     private ZenModeHelper mZenModeHelper;
992
993     private final Runnable mBuzzBeepBlinked = new Runnable() {
994         @Override
995         public void run() {
996             if (mStatusBar != null) {
997                 mStatusBar.buzzBeepBlinked();
998             }
999         }
1000     };
1001
1002     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1003         int[] ar = r.getIntArray(resid);
1004         if (ar == null) {
1005             return def;
1006         }
1007         final int len = ar.length > maxlen ? maxlen : ar.length;
1008         long[] out = new long[len];
1009         for (int i=0; i<len; i++) {
1010             out[i] = ar[i];
1011         }
1012         return out;
1013     }
1014
1015     public NotificationManagerService(Context context) {
1016         super(context);
1017     }
1018
1019     @VisibleForTesting
1020     void setAudioManager(AudioManager audioMananger) {
1021         mAudioManager = audioMananger;
1022     }
1023
1024     @VisibleForTesting
1025     void setVibrator(Vibrator vibrator) {
1026         mVibrator = vibrator;
1027     }
1028
1029     @VisibleForTesting
1030     void setSystemReady(boolean systemReady) {
1031         mSystemReady = systemReady;
1032     }
1033
1034     @VisibleForTesting
1035     void setHandler(Handler handler) {
1036         mHandler = handler;
1037     }
1038
1039     @Override
1040     public void onStart() {
1041         Resources resources = getContext().getResources();
1042
1043         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1044                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1045                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1046
1047         mAm = ActivityManagerNative.getDefault();
1048         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1049         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1050         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1051         mKeyguardManager =
1052                 (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
1053
1054         // This is the package that contains the AOSP framework update.
1055         mRankerServicePackageName = getContext().getPackageManager()
1056                 .getServicesSystemSharedLibraryPackageName();
1057
1058         mHandler = new WorkerHandler();
1059         mRankingThread.start();
1060         String[] extractorNames;
1061         try {
1062             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1063         } catch (Resources.NotFoundException e) {
1064             extractorNames = new String[0];
1065         }
1066         mUsageStats = new NotificationUsageStats(getContext());
1067         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1068         mRankingHelper = new RankingHelper(getContext(),
1069                 mRankingHandler,
1070                 mUsageStats,
1071                 extractorNames);
1072         mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
1073         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1074         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1075             @Override
1076             public void onConfigChanged() {
1077                 savePolicyFile();
1078             }
1079
1080             @Override
1081             void onZenModeChanged() {
1082                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1083                 getContext().sendBroadcastAsUser(
1084                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1085                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1086                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1087                 synchronized(mNotificationList) {
1088                     updateInterruptionFilterLocked();
1089                 }
1090             }
1091
1092             @Override
1093             void onPolicyChanged() {
1094                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1095             }
1096         });
1097         final File systemDir = new File(Environment.getDataDirectory(), "system");
1098         mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
1099
1100         syncBlockDb();
1101
1102         // This is a MangedServices object that keeps track of the listeners.
1103         mListeners = new NotificationListeners();
1104
1105         // This is a MangedServices object that keeps track of the ranker.
1106         mRankerServices = new NotificationRankers();
1107         // Find the updatable ranker and register it.
1108         mRankerServices.registerRanker();
1109
1110         mStatusBar = getLocalService(StatusBarManagerInternal.class);
1111         if (mStatusBar != null) {
1112             mStatusBar.setNotificationDelegate(mNotificationDelegate);
1113         }
1114
1115         final LightsManager lights = getLocalService(LightsManager.class);
1116         mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1117         mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
1118
1119         mDefaultNotificationColor = resources.getColor(
1120                 R.color.config_defaultNotificationColor);
1121         mDefaultNotificationLedOn = resources.getInteger(
1122                 R.integer.config_defaultNotificationLedOn);
1123         mDefaultNotificationLedOff = resources.getInteger(
1124                 R.integer.config_defaultNotificationLedOff);
1125
1126         mMultiColorNotificationLed = resources.getBoolean(
1127                 R.bool.config_multiColorNotificationLed);
1128
1129         mNotificationPulseCustomLedValues = new ArrayMap<String, NotificationLedValues>();
1130
1131         mPackageNameMappings = new ArrayMap<String, String>();
1132         final String[] defaultMapping = resources.getStringArray(
1133                 com.android.internal.R.array.notification_light_package_mapping);
1134         for (String mapping : defaultMapping) {
1135             String[] map = mapping.split("\\|");
1136             mPackageNameMappings.put(map[0], map[1]);
1137         }
1138
1139         mDefaultVibrationPattern = getLongArray(resources,
1140                 R.array.config_defaultNotificationVibePattern,
1141                 VIBRATE_PATTERN_MAXLEN,
1142                 DEFAULT_VIBRATE_PATTERN);
1143
1144         mFallbackVibrationPattern = getLongArray(resources,
1145                 R.array.config_notificationFallbackVibePattern,
1146                 VIBRATE_PATTERN_MAXLEN,
1147                 DEFAULT_VIBRATE_PATTERN);
1148
1149         mAdjustableNotificationLedBrightness = resources.getBoolean(
1150                 org.cyanogenmod.platform.internal.R.bool.config_adjustableNotificationLedBrightness);
1151         mMultipleNotificationLeds = resources.getBoolean(
1152                 org.cyanogenmod.platform.internal.R.bool.config_multipleNotificationLeds);
1153
1154         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1155
1156         // Don't start allowing notifications until the setup wizard has run once.
1157         // After that, including subsequent boots, init with notifications turned on.
1158         // This works on the first boot because the setup wizard will toggle this
1159         // flag at least once and we'll go back to 0 after that.
1160         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1161                     Settings.Global.DEVICE_PROVISIONED, 0)) {
1162             mDisableNotificationEffects = true;
1163         }
1164         mZenModeHelper.initZenMode();
1165         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1166
1167         mUserProfiles.updateCache(getContext());
1168         listenForCallState();
1169
1170         // register for various Intents
1171         IntentFilter filter = new IntentFilter();
1172         filter.addAction(Intent.ACTION_SCREEN_ON);
1173         filter.addAction(Intent.ACTION_SCREEN_OFF);
1174         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1175         filter.addAction(Intent.ACTION_USER_PRESENT);
1176         filter.addAction(Intent.ACTION_USER_STOPPED);
1177         filter.addAction(Intent.ACTION_USER_SWITCHED);
1178         filter.addAction(Intent.ACTION_USER_ADDED);
1179         filter.addAction(Intent.ACTION_USER_REMOVED);
1180         filter.addAction(Intent.ACTION_USER_UNLOCKED);
1181         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1182         getContext().registerReceiver(mIntentReceiver, filter);
1183
1184         IntentFilter pkgFilter = new IntentFilter();
1185         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1186         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1187         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1188         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1189         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1190         pkgFilter.addDataScheme("package");
1191         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1192                 null);
1193
1194         IntentFilter suspendedPkgFilter = new IntentFilter();
1195         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1196         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1197                 suspendedPkgFilter, null, null);
1198
1199         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1200         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1201                 null);
1202
1203         mSettingsObserver = new LEDSettingsObserver(mHandler);
1204         mSettingsObserver.observe();
1205
1206         mArchive = new Archive(resources.getInteger(
1207                 R.integer.config_notificationServiceArchiveSize));
1208
1209         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1210         publishLocalService(NotificationManagerInternal.class, mInternalService);
1211         mConfigManager = (CarrierConfigManager)
1212                 getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
1213     }
1214
1215     private void sendRegisteredOnlyBroadcast(String action) {
1216         getContext().sendBroadcastAsUser(new Intent(action)
1217                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1218     }
1219
1220     /**
1221      * Make sure the XML config and the the AppOps system agree about blocks.
1222      */
1223     private void syncBlockDb() {
1224         loadPolicyFile();
1225
1226         // sync bans from ranker into app opps
1227         Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1228         for(Entry<Integer, String> ban : packageBans.entrySet()) {
1229             final int uid = ban.getKey();
1230             final String packageName = ban.getValue();
1231             setNotificationsEnabledForPackageImpl(packageName, uid, false);
1232         }
1233
1234         // sync bans from app opps into ranker
1235         packageBans.clear();
1236         for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1237             final int userId = user.getUserHandle().getIdentifier();
1238             final PackageManager packageManager = getContext().getPackageManager();
1239             List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1240             final int packageCount = packages.size();
1241             for (int p = 0; p < packageCount; p++) {
1242                 final String packageName = packages.get(p).packageName;
1243                 try {
1244                     final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1245                     if (!checkNotificationOp(packageName, uid)) {
1246                         packageBans.put(uid, packageName);
1247                     }
1248                 } catch (NameNotFoundException e) {
1249                     // forget you
1250                 }
1251             }
1252         }
1253         for (Entry<Integer, String> ban : packageBans.entrySet()) {
1254             mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1255         }
1256
1257         savePolicyFile();
1258     }
1259
1260     @Override
1261     public void onBootPhase(int phase) {
1262         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1263             // no beeping until we're basically done booting
1264             mSystemReady = true;
1265
1266             // Grab our optional AudioService
1267             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1268             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1269             mVrManagerInternal = getLocalService(VrManagerInternal.class);
1270             mZenModeHelper.onSystemReady();
1271         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1272             // This observer will force an update when observe is called, causing us to
1273             // bind to listener services.
1274             mSettingsObserver.observe();
1275             mListeners.onBootPhaseAppsCanStart();
1276             mRankerServices.onBootPhaseAppsCanStart();
1277             mConditionProviders.onBootPhaseAppsCanStart();
1278         }
1279     }
1280
1281     void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1282         Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1283
1284         mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1285                 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1286
1287         // Now, cancel any outstanding notifications that are part of a just-disabled app
1288         if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1289             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
1290                     REASON_PACKAGE_BANNED, null);
1291         }
1292     }
1293
1294     private void updateListenerHintsLocked() {
1295         final int hints = calculateHints();
1296         if (hints == mListenerHints) return;
1297         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1298         mListenerHints = hints;
1299         scheduleListenerHintsChanged(hints);
1300     }
1301
1302     private void updateEffectsSuppressorLocked() {
1303         final long updatedSuppressedEffects = calculateSuppressedEffects();
1304         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1305         final List<ComponentName> suppressors = getSuppressors();
1306         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1307         mEffectsSuppressors = suppressors;
1308         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1309         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1310     }
1311
1312     private ArrayList<ComponentName> getSuppressors() {
1313         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1314         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1315             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1316
1317             for (ManagedServiceInfo info : serviceInfoList) {
1318                 names.add(info.component);
1319             }
1320         }
1321
1322         return names;
1323     }
1324
1325     private boolean removeDisabledHints(ManagedServiceInfo info) {
1326         return removeDisabledHints(info, 0);
1327     }
1328
1329     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1330         boolean removed = false;
1331
1332         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1333             final int hint = mListenersDisablingEffects.keyAt(i);
1334             final ArraySet<ManagedServiceInfo> listeners =
1335                     mListenersDisablingEffects.valueAt(i);
1336
1337             if (hints == 0 || (hint & hints) == hint) {
1338                 removed = removed || listeners.remove(info);
1339             }
1340         }
1341
1342         return removed;
1343     }
1344
1345     private void addDisabledHints(ManagedServiceInfo info, int hints) {
1346         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1347             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1348         }
1349
1350         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1351             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1352         }
1353
1354         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1355             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1356         }
1357     }
1358
1359     private void addDisabledHint(ManagedServiceInfo info, int hint) {
1360         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1361             mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1362         }
1363
1364         ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1365         hintListeners.add(info);
1366     }
1367
1368     private int calculateHints() {
1369         int hints = 0;
1370         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1371             int hint = mListenersDisablingEffects.keyAt(i);
1372             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1373
1374             if (!serviceInfoList.isEmpty()) {
1375                 hints |= hint;
1376             }
1377         }
1378
1379         return hints;
1380     }
1381
1382     private long calculateSuppressedEffects() {
1383         int hints = calculateHints();
1384         long suppressedEffects = 0;
1385
1386         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1387             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1388         }
1389
1390         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1391             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1392         }
1393
1394         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1395             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1396         }
1397
1398         return suppressedEffects;
1399     }
1400
1401     private void updateInterruptionFilterLocked() {
1402         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1403         if (interruptionFilter == mInterruptionFilter) return;
1404         mInterruptionFilter = interruptionFilter;
1405         scheduleInterruptionFilterChanged(interruptionFilter);
1406     }
1407
1408     private final IBinder mService = new INotificationManager.Stub() {
1409         // Toasts
1410         // ============================================================================
1411
1412         @Override
1413         public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1414         {
1415             if (DBG) {
1416                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1417                         + " duration=" + duration);
1418             }
1419
1420             if (pkg == null || callback == null) {
1421                 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1422                 return ;
1423             }
1424
1425             final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1426             final boolean isPackageSuspended =
1427                     isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1428
1429             if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1430                     || isPackageSuspended)) {
1431                 if (!isSystemToast) {
1432                     Slog.e(TAG, "Suppressing toast from package " + pkg
1433                             + (isPackageSuspended
1434                                     ? " due to package suspended by administrator."
1435                                     : " by user request."));
1436                     return;
1437                 }
1438             }
1439
1440             synchronized (mToastQueue) {
1441                 int callingPid = Binder.getCallingPid();
1442                 long callingId = Binder.clearCallingIdentity();
1443                 try {
1444                     ToastRecord record;
1445                     int index = indexOfToastLocked(pkg, callback);
1446                     // If it's already in the queue, we update it in place, we don't
1447                     // move it to the end of the queue.
1448                     if (index >= 0) {
1449                         record = mToastQueue.get(index);
1450                         record.update(duration);
1451                     } else {
1452                         // Limit the number of toasts that any given package except the android
1453                         // package can enqueue.  Prevents DOS attacks and deals with leaks.
1454                         if (!isSystemToast) {
1455                             int count = 0;
1456                             final int N = mToastQueue.size();
1457                             for (int i=0; i<N; i++) {
1458                                  final ToastRecord r = mToastQueue.get(i);
1459                                  if (r.pkg.equals(pkg)) {
1460                                      count++;
1461                                      if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1462                                          Slog.e(TAG, "Package has already posted " + count
1463                                                 + " toasts. Not showing more. Package=" + pkg);
1464                                          return;
1465                                      }
1466                                  }
1467                             }
1468                         }
1469
1470                         record = new ToastRecord(callingPid, pkg, callback, duration);
1471                         mToastQueue.add(record);
1472                         index = mToastQueue.size() - 1;
1473                         keepProcessAliveLocked(callingPid);
1474                     }
1475                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
1476                     // new or just been updated.  Call back and tell it to show itself.
1477                     // If the callback fails, this will remove it from the list, so don't
1478                     // assume that it's valid after this.
1479                     if (index == 0) {
1480                         showNextToastLocked();
1481                     }
1482                 } finally {
1483                     Binder.restoreCallingIdentity(callingId);
1484                 }
1485             }
1486         }
1487
1488         @Override
1489         public void cancelToast(String pkg, ITransientNotification callback) {
1490             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1491
1492             if (pkg == null || callback == null) {
1493                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1494                 return ;
1495             }
1496
1497             synchronized (mToastQueue) {
1498                 long callingId = Binder.clearCallingIdentity();
1499                 try {
1500                     int index = indexOfToastLocked(pkg, callback);
1501                     if (index >= 0) {
1502                         cancelToastLocked(index);
1503                     } else {
1504                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1505                                 + " callback=" + callback);
1506                     }
1507                 } finally {
1508                     Binder.restoreCallingIdentity(callingId);
1509                 }
1510             }
1511         }
1512
1513         @Override
1514         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1515                 Notification notification, int[] idOut, int userId) throws RemoteException {
1516             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1517                     Binder.getCallingPid(), tag, id, notification, idOut, userId);
1518         }
1519
1520         @Override
1521         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1522             checkCallerIsSystemOrSameApp(pkg);
1523             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1524                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1525             // Don't allow client applications to cancel foreground service notis or autobundled
1526             // summaries.
1527             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1528                     (Binder.getCallingUid() == Process.SYSTEM_UID
1529                             ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1530                             | (Binder.getCallingUid() == Process.SYSTEM_UID
1531                             ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1532                     REASON_APP_CANCEL, null);
1533         }
1534
1535         @Override
1536         public void cancelAllNotifications(String pkg, int userId) {
1537             checkCallerIsSystemOrSameApp(pkg);
1538
1539             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1540                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1541
1542             // Calling from user space, don't allow the canceling of actively
1543             // running foreground services.
1544             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1545                     pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1546                     REASON_APP_CANCEL_ALL, null);
1547         }
1548
1549         @Override
1550         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1551             checkCallerIsSystem();
1552
1553             setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1554             mRankingHelper.setEnabled(pkg, uid, enabled);
1555             savePolicyFile();
1556         }
1557
1558         /**
1559          * Use this when you just want to know if notifications are OK for this package.
1560          */
1561         @Override
1562         public boolean areNotificationsEnabled(String pkg) {
1563             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1564         }
1565
1566         /**
1567          * Use this when you just want to know if notifications are OK for this package.
1568          */
1569         @Override
1570         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1571             checkCallerIsSystemOrSameApp(pkg);
1572             return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1573                     == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1574         }
1575
1576         @Override
1577         public void setPriority(String pkg, int uid, int priority) {
1578             checkCallerIsSystem();
1579             mRankingHelper.setPriority(pkg, uid, priority);
1580             savePolicyFile();
1581         }
1582
1583         @Override
1584         public int getPriority(String pkg, int uid) {
1585             checkCallerIsSystem();
1586             return mRankingHelper.getPriority(pkg, uid);
1587         }
1588
1589         @Override
1590         public void setVisibilityOverride(String pkg, int uid, int visibility) {
1591             checkCallerIsSystem();
1592             mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
1593             savePolicyFile();
1594         }
1595
1596         @Override
1597         public int getVisibilityOverride(String pkg, int uid) {
1598             checkCallerIsSystem();
1599             return mRankingHelper.getVisibilityOverride(pkg, uid);
1600         }
1601
1602         @Override
1603         public void setImportance(String pkg, int uid, int importance) {
1604             enforceSystemOrSystemUI("Caller not system or systemui");
1605             setNotificationsEnabledForPackageImpl(pkg, uid,
1606                     importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1607             mRankingHelper.setImportance(pkg, uid, importance);
1608             savePolicyFile();
1609         }
1610
1611         @Override
1612         public int getPackageImportance(String pkg) {
1613             checkCallerIsSystemOrSameApp(pkg);
1614             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1615         }
1616
1617         @Override
1618         public int getImportance(String pkg, int uid) {
1619             enforceSystemOrSystemUI("Caller not system or systemui");
1620             return mRankingHelper.getImportance(pkg, uid);
1621         }
1622
1623         /**
1624          * System-only API for getting a list of current (i.e. not cleared) notifications.
1625          *
1626          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1627          * @returns A list of all the notifications, in natural order.
1628          */
1629         @Override
1630         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1631             // enforce() will ensure the calling uid has the correct permission
1632             getContext().enforceCallingOrSelfPermission(
1633                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1634                     "NotificationManagerService.getActiveNotifications");
1635
1636             StatusBarNotification[] tmp = null;
1637             int uid = Binder.getCallingUid();
1638
1639             // noteOp will check to make sure the callingPkg matches the uid
1640             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1641                     == AppOpsManager.MODE_ALLOWED) {
1642                 synchronized (mNotificationList) {
1643                     tmp = new StatusBarNotification[mNotificationList.size()];
1644                     final int N = mNotificationList.size();
1645                     for (int i=0; i<N; i++) {
1646                         tmp[i] = mNotificationList.get(i).sbn;
1647                     }
1648                 }
1649             }
1650             return tmp;
1651         }
1652
1653         /**
1654          * Public API for getting a list of current notifications for the calling package/uid.
1655          *
1656          * @returns A list of all the package's notifications, in natural order.
1657          */
1658         @Override
1659         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1660                 int incomingUserId) {
1661             checkCallerIsSystemOrSameApp(pkg);
1662             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1663                     Binder.getCallingUid(), incomingUserId, true, false,
1664                     "getAppActiveNotifications", pkg);
1665
1666             final ArrayList<StatusBarNotification> list
1667                     = new ArrayList<StatusBarNotification>(mNotificationList.size());
1668
1669             synchronized (mNotificationList) {
1670                 final int N = mNotificationList.size();
1671                 for (int i = 0; i < N; i++) {
1672                     final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1673                     if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1674                             && (sbn.getNotification().flags
1675                             & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1676                         // We could pass back a cloneLight() but clients might get confused and
1677                         // try to send this thing back to notify() again, which would not work
1678                         // very well.
1679                         final StatusBarNotification sbnOut = new StatusBarNotification(
1680                                 sbn.getPackageName(),
1681                                 sbn.getOpPkg(),
1682                                 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1683                                 0, // hide score from apps
1684                                 sbn.getNotification().clone(),
1685                                 sbn.getUser(), sbn.getPostTime());
1686                         list.add(sbnOut);
1687                     }
1688                 }
1689             }
1690
1691             return new ParceledListSlice<StatusBarNotification>(list);
1692         }
1693
1694         /**
1695          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1696          *
1697          * Requires ACCESS_NOTIFICATIONS which is signature|system.
1698          */
1699         @Override
1700         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1701             // enforce() will ensure the calling uid has the correct permission
1702             getContext().enforceCallingOrSelfPermission(
1703                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
1704                     "NotificationManagerService.getHistoricalNotifications");
1705
1706             StatusBarNotification[] tmp = null;
1707             int uid = Binder.getCallingUid();
1708
1709             // noteOp will check to make sure the callingPkg matches the uid
1710             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1711                     == AppOpsManager.MODE_ALLOWED) {
1712                 synchronized (mArchive) {
1713                     tmp = mArchive.getArray(count);
1714                 }
1715             }
1716             return tmp;
1717         }
1718
1719         /**
1720          * Register a listener binder directly with the notification manager.
1721          *
1722          * Only works with system callers. Apps should extend
1723          * {@link android.service.notification.NotificationListenerService}.
1724          */
1725         @Override
1726         public void registerListener(final INotificationListener listener,
1727                 final ComponentName component, final int userid) {
1728             enforceSystemOrSystemUI("INotificationManager.registerListener");
1729             mListeners.registerService(listener, component, userid);
1730         }
1731
1732         /**
1733          * Remove a listener binder directly
1734          */
1735         @Override
1736         public void unregisterListener(INotificationListener token, int userid) {
1737             mListeners.unregisterService(token, userid);
1738         }
1739
1740         /**
1741          * Allow an INotificationListener to simulate a "clear all" operation.
1742          *
1743          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1744          *
1745          * @param token The binder for the listener, to check that the caller is allowed
1746          */
1747         @Override
1748         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1749             final int callingUid = Binder.getCallingUid();
1750             final int callingPid = Binder.getCallingPid();
1751             long identity = Binder.clearCallingIdentity();
1752             try {
1753                 synchronized (mNotificationList) {
1754                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1755                     if (keys != null) {
1756                         final int N = keys.length;
1757                         for (int i = 0; i < N; i++) {
1758                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
1759                             if (r == null) continue;
1760                             final int userId = r.sbn.getUserId();
1761                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
1762                                     !mUserProfiles.isCurrentProfile(userId)) {
1763                                 throw new SecurityException("Disallowed call from listener: "
1764                                         + info.service);
1765                             }
1766                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1767                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1768                                     userId);
1769                         }
1770                     } else {
1771                         cancelAllLocked(callingUid, callingPid, info.userid,
1772                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1773                     }
1774                 }
1775             } finally {
1776                 Binder.restoreCallingIdentity(identity);
1777             }
1778         }
1779
1780         /**
1781          * Handle request from an approved listener to re-enable itself.
1782          *
1783          * @param component The componenet to be re-enabled, caller must match package.
1784          */
1785         @Override
1786         public void requestBindListener(ComponentName component) {
1787             checkCallerIsSystemOrSameApp(component.getPackageName());
1788             long identity = Binder.clearCallingIdentity();
1789             try {
1790                 ManagedServices manager =
1791                         mRankerServices.isComponentEnabledForCurrentProfiles(component)
1792                         ? mRankerServices
1793                         : mListeners;
1794                 manager.setComponentState(component, true);
1795             } finally {
1796                 Binder.restoreCallingIdentity(identity);
1797             }
1798         }
1799
1800         @Override
1801         public void requestUnbindListener(INotificationListener token) {
1802             long identity = Binder.clearCallingIdentity();
1803             try {
1804                 // allow bound services to disable themselves
1805                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1806                 info.getOwner().setComponentState(info.component, false);
1807             } finally {
1808                 Binder.restoreCallingIdentity(identity);
1809             }
1810         }
1811
1812         @Override
1813         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
1814             long identity = Binder.clearCallingIdentity();
1815             try {
1816                 synchronized (mNotificationList) {
1817                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1818                     if (keys != null) {
1819                         final int N = keys.length;
1820                         for (int i = 0; i < N; i++) {
1821                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
1822                             if (r == null) continue;
1823                             final int userId = r.sbn.getUserId();
1824                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
1825                                     !mUserProfiles.isCurrentProfile(userId)) {
1826                                 throw new SecurityException("Disallowed call from listener: "
1827                                         + info.service);
1828                             }
1829                             if (!r.isSeen()) {
1830                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1831                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1832                                         userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1833                                                 : userId,
1834                                         UsageEvents.Event.USER_INTERACTION);
1835                                 r.setSeen();
1836                             }
1837                         }
1838                     }
1839                 }
1840             } finally {
1841                 Binder.restoreCallingIdentity(identity);
1842             }
1843         }
1844
1845         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1846                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1847             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1848                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1849                     true,
1850                     userId, REASON_LISTENER_CANCEL, info);
1851         }
1852
1853         /**
1854          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1855          *
1856          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1857          *
1858          * @param token The binder for the listener, to check that the caller is allowed
1859          */
1860         @Override
1861         public void cancelNotificationFromListener(INotificationListener token, String pkg,
1862                 String tag, int id) {
1863             final int callingUid = Binder.getCallingUid();
1864             final int callingPid = Binder.getCallingPid();
1865             long identity = Binder.clearCallingIdentity();
1866             try {
1867                 synchronized (mNotificationList) {
1868                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1869                     if (info.supportsProfiles()) {
1870                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1871                                 + "from " + info.component
1872                                 + " use cancelNotification(key) instead.");
1873                     } else {
1874                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1875                                 pkg, tag, id, info.userid);
1876                     }
1877                 }
1878             } finally {
1879                 Binder.restoreCallingIdentity(identity);
1880             }
1881         }
1882
1883         /**
1884          * Allow an INotificationListener to request the list of outstanding notifications seen by
1885          * the current user. Useful when starting up, after which point the listener callbacks
1886          * should be used.
1887          *
1888          * @param token The binder for the listener, to check that the caller is allowed
1889          * @param keys An array of notification keys to fetch, or null to fetch everything
1890          * @returns The return value will contain the notifications specified in keys, in that
1891          *      order, or if keys is null, all the notifications, in natural order.
1892          */
1893         @Override
1894         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1895                 INotificationListener token, String[] keys, int trim) {
1896             synchronized (mNotificationList) {
1897                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1898                 final boolean getKeys = keys != null;
1899                 final int N = getKeys ? keys.length : mNotificationList.size();
1900                 final ArrayList<StatusBarNotification> list
1901                         = new ArrayList<StatusBarNotification>(N);
1902                 for (int i=0; i<N; i++) {
1903                     final NotificationRecord r = getKeys
1904                             ? mNotificationsByKey.get(keys[i])
1905                             : mNotificationList.get(i);
1906                     if (r == null) continue;
1907                     StatusBarNotification sbn = r.sbn;
1908                     if (!isVisibleToListener(sbn, info)) continue;
1909                     StatusBarNotification sbnToSend =
1910                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1911                     list.add(sbnToSend);
1912                 }
1913                 return new ParceledListSlice<StatusBarNotification>(list);
1914             }
1915         }
1916
1917         @Override
1918         public void requestHintsFromListener(INotificationListener token, int hints) {
1919             final long identity = Binder.clearCallingIdentity();
1920             try {
1921                 synchronized (mNotificationList) {
1922                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1923                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1924                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1925                             | HINT_HOST_DISABLE_CALL_EFFECTS;
1926                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
1927                     if (disableEffects) {
1928                         addDisabledHints(info, hints);
1929                     } else {
1930                         removeDisabledHints(info, hints);
1931                     }
1932                     updateListenerHintsLocked();
1933                     updateEffectsSuppressorLocked();
1934                 }
1935             } finally {
1936                 Binder.restoreCallingIdentity(identity);
1937             }
1938         }
1939
1940         @Override
1941         public int getHintsFromListener(INotificationListener token) {
1942             synchronized (mNotificationList) {
1943                 return mListenerHints;
1944             }
1945         }
1946
1947         @Override
1948         public void requestInterruptionFilterFromListener(INotificationListener token,
1949                 int interruptionFilter) throws RemoteException {
1950             final long identity = Binder.clearCallingIdentity();
1951             try {
1952                 synchronized (mNotificationList) {
1953                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1954                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
1955                     updateInterruptionFilterLocked();
1956                 }
1957             } finally {
1958                 Binder.restoreCallingIdentity(identity);
1959             }
1960         }
1961
1962         @Override
1963         public int getInterruptionFilterFromListener(INotificationListener token)
1964                 throws RemoteException {
1965             synchronized (mNotificationLight) {
1966                 return mInterruptionFilter;
1967             }
1968         }
1969
1970         @Override
1971         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1972                 throws RemoteException {
1973             synchronized (mNotificationList) {
1974                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1975                 if (info == null) return;
1976                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1977             }
1978         }
1979
1980         @Override
1981         public int getZenMode() {
1982             return mZenModeHelper.getZenMode();
1983         }
1984
1985         @Override
1986         public ZenModeConfig getZenModeConfig() {
1987             enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
1988             return mZenModeHelper.getConfig();
1989         }
1990
1991         @Override
1992         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
1993             enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1994             final long identity = Binder.clearCallingIdentity();
1995             try {
1996                 mZenModeHelper.setManualZenMode(mode, conditionId, reason);
1997             } finally {
1998                 Binder.restoreCallingIdentity(identity);
1999             }
2000         }
2001
2002         @Override
2003         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2004             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2005             return mZenModeHelper.getZenRules();
2006         }
2007
2008         @Override
2009         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2010             Preconditions.checkNotNull(id, "Id is null");
2011             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2012             return mZenModeHelper.getAutomaticZenRule(id);
2013         }
2014
2015         @Override
2016         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2017                 throws RemoteException {
2018             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2019             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2020             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2021             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2022             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2023
2024             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2025                     "addAutomaticZenRule");
2026         }
2027
2028         @Override
2029         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2030                 throws RemoteException {
2031             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2032             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2033             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2034             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2035             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2036
2037             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2038                     "updateAutomaticZenRule");
2039         }
2040
2041         @Override
2042         public boolean removeAutomaticZenRule(String id) throws RemoteException {
2043             Preconditions.checkNotNull(id, "Id is null");
2044             // Verify that they can modify zen rules.
2045             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2046
2047             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2048         }
2049
2050         @Override
2051         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2052             Preconditions.checkNotNull(packageName, "Package name is null");
2053             enforceSystemOrSystemUI("removeAutomaticZenRules");
2054
2055             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2056         }
2057
2058         @Override
2059         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2060             Preconditions.checkNotNull(owner, "Owner is null");
2061             enforceSystemOrSystemUI("getRuleInstanceCount");
2062
2063             return mZenModeHelper.getCurrentInstanceCount(owner);
2064         }
2065
2066         @Override
2067         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2068             enforcePolicyAccess(pkg, "setInterruptionFilter");
2069             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2070             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2071             final long identity = Binder.clearCallingIdentity();
2072             try {
2073                 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
2074             } finally {
2075                 Binder.restoreCallingIdentity(identity);
2076             }
2077         }
2078
2079         @Override
2080         public void notifyConditions(final String pkg, IConditionProvider provider,
2081                 final Condition[] conditions) {
2082             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2083             checkCallerIsSystemOrSameApp(pkg);
2084             mHandler.post(new Runnable() {
2085                 @Override
2086                 public void run() {
2087                     mConditionProviders.notifyConditions(pkg, info, conditions);
2088                 }
2089             });
2090         }
2091
2092         private void enforceSystemOrSystemUIOrVolume(String message) {
2093             if (mAudioManagerInternal != null) {
2094                 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
2095                 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
2096                     return;
2097                 }
2098             }
2099             enforceSystemOrSystemUI(message);
2100         }
2101
2102         private void enforceSystemOrSystemUI(String message) {
2103             if (isCallerSystem()) return;
2104             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2105                     message);
2106         }
2107
2108         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2109             try {
2110                 checkCallerIsSystemOrSameApp(pkg);
2111             } catch (SecurityException e) {
2112                 getContext().enforceCallingPermission(
2113                         android.Manifest.permission.STATUS_BAR_SERVICE,
2114                         message);
2115             }
2116         }
2117
2118         private void enforcePolicyAccess(int uid, String method) {
2119             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2120                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2121                 return;
2122             }
2123             boolean accessAllowed = false;
2124             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2125             final int packageCount = packages.length;
2126             for (int i = 0; i < packageCount; i++) {
2127                 if (checkPolicyAccess(packages[i])) {
2128                     accessAllowed = true;
2129                 }
2130             }
2131             if (!accessAllowed) {
2132                 Slog.w(TAG, "Notification policy access denied calling " + method);
2133                 throw new SecurityException("Notification policy access denied");
2134             }
2135         }
2136
2137         private void enforcePolicyAccess(String pkg, String method) {
2138             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2139                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2140                 return;
2141             }
2142             checkCallerIsSameApp(pkg);
2143             if (!checkPolicyAccess(pkg)) {
2144                 Slog.w(TAG, "Notification policy access denied calling " + method);
2145                 throw new SecurityException("Notification policy access denied");
2146             }
2147         }
2148
2149         private boolean checkPackagePolicyAccess(String pkg) {
2150             return mPolicyAccess.isPackageGranted(pkg);
2151         }
2152
2153         private boolean checkPolicyAccess(String pkg) {
2154             try {
2155                 int uid = getContext().getPackageManager().getPackageUidAsUser(
2156                         pkg, UserHandle.getCallingUserId());
2157                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2158                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2159                         -1, true)) {
2160                     return true;
2161                 }
2162             } catch (NameNotFoundException e) {
2163                 return false;
2164             }
2165             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2166         }
2167
2168         @Override
2169         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2170             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2171                     != PackageManager.PERMISSION_GRANTED) {
2172                 pw.println("Permission Denial: can't dump NotificationManager from pid="
2173                         + Binder.getCallingPid()
2174                         + ", uid=" + Binder.getCallingUid());
2175                 return;
2176             }
2177
2178             final DumpFilter filter = DumpFilter.parseFromArguments(args);
2179             if (filter != null && filter.stats) {
2180                 dumpJson(pw, filter);
2181             } else {
2182                 dumpImpl(pw, filter);
2183             }
2184         }
2185
2186         @Override
2187         public ComponentName getEffectsSuppressor() {
2188             enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
2189             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2190         }
2191
2192         @Override
2193         public boolean matchesCallFilter(Bundle extras) {
2194             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2195             return mZenModeHelper.matchesCallFilter(
2196                     Binder.getCallingUserHandle(),
2197                     extras,
2198                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2199                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2200                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2201         }
2202
2203         @Override
2204         public boolean isSystemConditionProviderEnabled(String path) {
2205             enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
2206             return mConditionProviders.isSystemProviderEnabled(path);
2207         }
2208
2209         // Backup/restore interface
2210         @Override
2211         public byte[] getBackupPayload(int user) {
2212             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2213             //TODO: http://b/22388012
2214             if (user != UserHandle.USER_SYSTEM) {
2215                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2216                 return null;
2217             }
2218             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2219             try {
2220                 writePolicyXml(baos, true /*forBackup*/);
2221                 return baos.toByteArray();
2222             } catch (IOException e) {
2223                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2224             }
2225             return null;
2226         }
2227
2228         @Override
2229         public void applyRestore(byte[] payload, int user) {
2230             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2231                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2232             if (payload == null) {
2233                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2234                 return;
2235             }
2236             //TODO: http://b/22388012
2237             if (user != UserHandle.USER_SYSTEM) {
2238                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2239                 return;
2240             }
2241             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2242             try {
2243                 readPolicyXml(bais, true /*forRestore*/);
2244                 savePolicyFile();
2245             } catch (NumberFormatException | XmlPullParserException | IOException e) {
2246                 Slog.w(TAG, "applyRestore: error reading payload", e);
2247             }
2248         }
2249
2250         @Override
2251         public boolean isNotificationPolicyAccessGranted(String pkg) {
2252             return checkPolicyAccess(pkg);
2253         }
2254
2255         @Override
2256         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2257             enforceSystemOrSystemUIOrSamePackage(pkg,
2258                     "request policy access status for another package");
2259             return checkPolicyAccess(pkg);
2260         }
2261
2262         @Override
2263         public String[] getPackagesRequestingNotificationPolicyAccess()
2264                 throws RemoteException {
2265             enforceSystemOrSystemUI("request policy access packages");
2266             final long identity = Binder.clearCallingIdentity();
2267             try {
2268                 return mPolicyAccess.getRequestingPackages();
2269             } finally {
2270                 Binder.restoreCallingIdentity(identity);
2271             }
2272         }
2273
2274         @Override
2275         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2276                 throws RemoteException {
2277             enforceSystemOrSystemUI("grant notification policy access");
2278             final long identity = Binder.clearCallingIdentity();
2279             try {
2280                 synchronized (mNotificationList) {
2281                     mPolicyAccess.put(pkg, granted);
2282                 }
2283             } finally {
2284                 Binder.restoreCallingIdentity(identity);
2285             }
2286         }
2287
2288         @Override
2289         public Policy getNotificationPolicy(String pkg) {
2290             enforcePolicyAccess(pkg, "getNotificationPolicy");
2291             final long identity = Binder.clearCallingIdentity();
2292             try {
2293                 return mZenModeHelper.getNotificationPolicy();
2294             } finally {
2295                 Binder.restoreCallingIdentity(identity);
2296             }
2297         }
2298
2299         @Override
2300         public void setNotificationPolicy(String pkg, Policy policy) {
2301             enforcePolicyAccess(pkg, "setNotificationPolicy");
2302             final long identity = Binder.clearCallingIdentity();
2303             try {
2304                 mZenModeHelper.setNotificationPolicy(policy);
2305             } finally {
2306                 Binder.restoreCallingIdentity(identity);
2307             }
2308         }
2309
2310         @Override
2311         public void applyAdjustmentFromRankerService(INotificationListener token,
2312                 Adjustment adjustment) throws RemoteException {
2313             final long identity = Binder.clearCallingIdentity();
2314             try {
2315                 synchronized (mNotificationList) {
2316                     mRankerServices.checkServiceTokenLocked(token);
2317                     applyAdjustmentLocked(adjustment);
2318                 }
2319                 maybeAddAutobundleSummary(adjustment);
2320                 mRankingHandler.requestSort();
2321             } finally {
2322                 Binder.restoreCallingIdentity(identity);
2323             }
2324         }
2325
2326         @Override
2327         public void applyAdjustmentsFromRankerService(INotificationListener token,
2328                 List<Adjustment> adjustments) throws RemoteException {
2329
2330             final long identity = Binder.clearCallingIdentity();
2331             try {
2332                 synchronized (mNotificationList) {
2333                     mRankerServices.checkServiceTokenLocked(token);
2334                     for (Adjustment adjustment : adjustments) {
2335                         applyAdjustmentLocked(adjustment);
2336                     }
2337                 }
2338                 for (Adjustment adjustment : adjustments) {
2339                     maybeAddAutobundleSummary(adjustment);
2340                 }
2341                 mRankingHandler.requestSort();
2342             } finally {
2343                 Binder.restoreCallingIdentity(identity);
2344             }
2345         }
2346     };
2347
2348     private void applyAdjustmentLocked(Adjustment adjustment) {
2349         maybeClearAutobundleSummaryLocked(adjustment);
2350         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2351         if (n == null) {
2352             return;
2353         }
2354         if (adjustment.getImportance() != IMPORTANCE_NONE) {
2355             n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2356         }
2357         if (adjustment.getSignals() != null) {
2358             Bundle.setDefusable(adjustment.getSignals(), true);
2359             final String autoGroupKey = adjustment.getSignals().getString(
2360                     Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2361             if (autoGroupKey == null) {
2362                 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2363             } else {
2364                 EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2365             }
2366             n.sbn.setOverrideGroupKey(autoGroupKey);
2367         }
2368     }
2369
2370     // Clears the 'fake' auto-bunding summary.
2371     private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
2372         if (adjustment.getSignals() != null) {
2373             Bundle.setDefusable(adjustment.getSignals(), true);
2374             if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
2375                 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2376                 ArrayMap<String, String> summaries =
2377                         mAutobundledSummaries.get(adjustment.getUser());
2378                 if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
2379                     // Clear summary.
2380                     final NotificationRecord removed = mNotificationsByKey.get(
2381                             summaries.remove(adjustment.getPackage()));
2382                     if (removed != null) {
2383                         mNotificationList.remove(removed);
2384                         cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2385                     }
2386                 }
2387             }
2388         }
2389     }
2390
2391     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2392     private void maybeAddAutobundleSummary(Adjustment adjustment) {
2393         if (adjustment.getSignals() != null) {
2394             Bundle.setDefusable(adjustment.getSignals(), true);
2395             if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2396                 final String newAutoBundleKey =
2397                         adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2398                 int userId = -1;
2399                 NotificationRecord summaryRecord = null;
2400                 synchronized (mNotificationList) {
2401                     NotificationRecord notificationRecord =
2402                             mNotificationsByKey.get(adjustment.getKey());
2403                     if (notificationRecord == null) {
2404                         // The notification could have been cancelled again already. A successive
2405                         // adjustment will post a summary if needed.
2406                         return;
2407                     }
2408                     final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2409                     userId = adjustedSbn.getUser().getIdentifier();
2410                     ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2411                     if (summaries == null) {
2412                         summaries = new ArrayMap<>();
2413                     }
2414                     mAutobundledSummaries.put(userId, summaries);
2415                     if (!summaries.containsKey(adjustment.getPackage())
2416                             && newAutoBundleKey != null) {
2417                         // Add summary
2418                         final ApplicationInfo appInfo =
2419                                 adjustedSbn.getNotification().extras.getParcelable(
2420                                         Notification.EXTRA_BUILDER_APPLICATION_INFO);
2421                         final Bundle extras = new Bundle();
2422                         extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2423                         final Notification summaryNotification =
2424                                 new Notification.Builder(getContext()).setSmallIcon(
2425                                         adjustedSbn.getNotification().getSmallIcon())
2426                                         .setGroupSummary(true)
2427                                         .setGroup(newAutoBundleKey)
2428                                         .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2429                                         .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2430                                         .setColor(adjustedSbn.getNotification().color)
2431                                         .build();
2432                         summaryNotification.extras.putAll(extras);
2433                         Intent appIntent = getContext().getPackageManager()
2434                                 .getLaunchIntentForPackage(adjustment.getPackage());
2435                         if (appIntent != null) {
2436                             summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2437                                     getContext(), 0, appIntent, 0, null,
2438                                     UserHandle.of(userId));
2439                         }
2440                         final StatusBarNotification summarySbn =
2441                                 new StatusBarNotification(adjustedSbn.getPackageName(),
2442                                         adjustedSbn.getOpPkg(),
2443                                         Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2444                                         adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2445                                         summaryNotification, adjustedSbn.getUser(),
2446                                         newAutoBundleKey,
2447                                         System.currentTimeMillis());
2448                         summaryRecord = new NotificationRecord(getContext(), summarySbn);
2449                         summaries.put(adjustment.getPackage(), summarySbn.getKey());
2450                     }
2451                 }
2452                 if (summaryRecord != null) {
2453                     mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2454                 }
2455             }
2456         }
2457     }
2458
2459     private String disableNotificationEffects(NotificationRecord record) {
2460         if (mDisableNotificationEffects) {
2461             return "booleanState";
2462         }
2463         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2464             return "listenerHints";
2465         }
2466         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2467             return "callState";
2468         }
2469         return null;
2470     };
2471
2472     private void dumpJson(PrintWriter pw, DumpFilter filter) {
2473         JSONObject dump = new JSONObject();
2474         try {
2475             dump.put("service", "Notification Manager");
2476             dump.put("bans", mRankingHelper.dumpBansJson(filter));
2477             dump.put("ranking", mRankingHelper.dumpJson(filter));
2478             dump.put("stats", mUsageStats.dumpJson(filter));
2479         } catch (JSONException e) {
2480             e.printStackTrace();
2481         }
2482         pw.println(dump);
2483     }
2484
2485     void dumpImpl(PrintWriter pw, DumpFilter filter) {
2486         pw.print("Current Notification Manager state");
2487         if (filter.filtered) {
2488             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2489         }
2490         pw.println(':');
2491         int N;
2492         final boolean zenOnly = filter.filtered && filter.zen;
2493
2494         if (!zenOnly) {
2495             synchronized (mToastQueue) {
2496                 N = mToastQueue.size();
2497                 if (N > 0) {
2498                     pw.println("  Toast Queue:");
2499                     for (int i=0; i<N; i++) {
2500                         mToastQueue.get(i).dump(pw, "    ", filter);
2501                     }
2502                     pw.println("  ");
2503                 }
2504             }
2505         }
2506
2507         synchronized (mNotificationList) {
2508             if (!zenOnly) {
2509                 N = mNotificationList.size();
2510                 if (N > 0) {
2511                     pw.println("  Notification List:");
2512                     for (int i=0; i<N; i++) {
2513                         final NotificationRecord nr = mNotificationList.get(i);
2514                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
2515                         nr.dump(pw, "    ", getContext(), filter.redact);
2516                     }
2517                     pw.println("  ");
2518                 }
2519
2520                 if (!filter.filtered) {
2521                     N = mLights.size();
2522                     if (N > 0) {
2523                         pw.println("  Lights List:");
2524                         for (int i=0; i<N; i++) {
2525                             if (i == N - 1) {
2526                                 pw.print("  > ");
2527                             } else {
2528                                 pw.print("    ");
2529                             }
2530                             pw.println(mLights.get(i));
2531                         }
2532                         pw.println("  ");
2533                     }
2534                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
2535                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2536                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
2537                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
2538                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
2539                     pw.println("  mCallState=" + callStateToString(mCallState));
2540                     pw.println("  mSystemReady=" + mSystemReady);
2541                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
2542                 }
2543                 pw.println("  mArchive=" + mArchive.toString());
2544                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2545                 int i=0;
2546                 while (iter.hasNext()) {
2547                     final StatusBarNotification sbn = iter.next();
2548                     if (filter != null && !filter.matches(sbn)) continue;
2549                     pw.println("    " + sbn);
2550                     if (++i >= 5) {
2551                         if (iter.hasNext()) pw.println("    ...");
2552                         break;
2553                     }
2554                 }
2555             }
2556
2557             if (!zenOnly) {
2558                 pw.println("\n  Usage Stats:");
2559                 mUsageStats.dump(pw, "    ", filter);
2560             }
2561
2562             if (!filter.filtered || zenOnly) {
2563                 pw.println("\n  Zen Mode:");
2564                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
2565                 mZenModeHelper.dump(pw, "    ");
2566
2567                 pw.println("\n  Zen Log:");
2568                 ZenLog.dump(pw, "    ");
2569             }
2570
2571             if (!zenOnly) {
2572                 pw.println("\n  Ranking Config:");
2573                 mRankingHelper.dump(pw, "    ", filter);
2574
2575                 pw.println("\n  Notification listeners:");
2576                 mListeners.dump(pw, filter);
2577                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
2578                 pw.print("    mListenersDisablingEffects: (");
2579                 N = mListenersDisablingEffects.size();
2580                 for (int i = 0; i < N; i++) {
2581                     final int hint = mListenersDisablingEffects.keyAt(i);
2582                     if (i > 0) pw.print(';');
2583                     pw.print("hint[" + hint + "]:");
2584
2585                     final ArraySet<ManagedServiceInfo> listeners =
2586                             mListenersDisablingEffects.valueAt(i);
2587                     final int listenerSize = listeners.size();
2588
2589                     for (int j = 0; j < listenerSize; j++) {
2590                         if (i > 0) pw.print(',');
2591                         final ManagedServiceInfo listener = listeners.valueAt(i);
2592                         pw.print(listener.component);
2593                     }
2594                 }
2595                 pw.println(')');
2596                 pw.println("\n  mRankerServicePackageName: " + mRankerServicePackageName);
2597                 pw.println("\n  Notification ranker services:");
2598                 mRankerServices.dump(pw, filter);
2599             }
2600             pw.println("\n  Policy access:");
2601             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
2602
2603             pw.println("\n  Condition providers:");
2604             mConditionProviders.dump(pw, filter);
2605
2606             pw.println("\n  Group summaries:");
2607             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2608                 NotificationRecord r = entry.getValue();
2609                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
2610                 if (mNotificationsByKey.get(r.getKey()) != r) {
2611                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2612                     r.dump(pw, "      ", getContext(), filter.redact);
2613                 }
2614             }
2615         }
2616     }
2617
2618     /**
2619      * The private API only accessible to the system process.
2620      */
2621     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2622         @Override
2623         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2624                 String tag, int id, Notification notification, int[] idReceived, int userId) {
2625             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2626                     idReceived, userId);
2627         }
2628
2629         @Override
2630         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2631                 int userId) {
2632             checkCallerIsSystem();
2633             synchronized (mNotificationList) {
2634                 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2635                 if (i < 0) {
2636                     Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2637                             + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2638                     return;
2639                 }
2640                 NotificationRecord r = mNotificationList.get(i);
2641                 StatusBarNotification sbn = r.sbn;
2642                 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2643                 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2644                 // we have to revert to the flags we received initially *and* force remove
2645                 // FLAG_FOREGROUND_SERVICE.
2646                 sbn.getNotification().flags =
2647                         (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2648                 mRankingHelper.sort(mNotificationList);
2649                 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2650             }
2651         }
2652     };
2653
2654     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2655             final int callingPid, final String tag, final int id, final Notification notification,
2656             int[] idOut, int incomingUserId) {
2657         if (DBG) {
2658             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2659                     + " notification=" + notification);
2660         }
2661         checkCallerIsSystemOrSameApp(pkg);
2662         final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2663         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2664
2665         final int userId = ActivityManager.handleIncomingUser(callingPid,
2666                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2667         final UserHandle user = new UserHandle(userId);
2668
2669         // Fix the notification as best we can.
2670         try {
2671             final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2672                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2673                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2674             Notification.addFieldsFromContext(ai, userId, notification);
2675         } catch (NameNotFoundException e) {
2676             Slog.e(TAG, "Cannot create a context for sending app", e);
2677             return;
2678         }
2679
2680         mUsageStats.registerEnqueuedByApp(pkg);
2681
2682         // Limit the number of notifications that any given package except the android
2683         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
2684         if (!isSystemNotification && !isNotificationFromListener) {
2685             synchronized (mNotificationList) {
2686                 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
2687                 if (appEnqueueRate > mMaxPackageEnqueueRate) {
2688                     mUsageStats.registerOverRateQuota(pkg);
2689                     final long now = SystemClock.elapsedRealtime();
2690                     if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2691                         Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2692                                 + ". Shedding events. package=" + pkg);
2693                         mLastOverRateLogTime = now;
2694                     }
2695                     return;
2696                 }
2697
2698                 int count = 0;
2699                 final int N = mNotificationList.size();
2700                 for (int i=0; i<N; i++) {
2701                     final NotificationRecord r = mNotificationList.get(i);
2702                     if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2703                         if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2704                             break;  // Allow updating existing notification
2705                         }
2706                         count++;
2707                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2708                             mUsageStats.registerOverCountQuota(pkg);
2709                             Slog.e(TAG, "Package has already posted " + count
2710                                     + " notifications.  Not showing more.  package=" + pkg);
2711                             return;
2712                         }
2713                     }
2714                 }
2715             }
2716         }
2717
2718         if (pkg == null || notification == null) {
2719             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2720                     + " id=" + id + " notification=" + notification);
2721         }
2722
2723         // Whitelist pending intents.
2724         if (notification.allPendingIntents != null) {
2725             final int intentCount = notification.allPendingIntents.size();
2726             if (intentCount > 0) {
2727                 final ActivityManagerInternal am = LocalServices
2728                         .getService(ActivityManagerInternal.class);
2729                 final long duration = LocalServices.getService(
2730                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
2731                 for (int i = 0; i < intentCount; i++) {
2732                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
2733                     if (pendingIntent != null) {
2734                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
2735                     }
2736                 }
2737             }
2738         }
2739
2740         // Sanitize inputs
2741         notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2742                 Notification.PRIORITY_MAX);
2743
2744         // setup local book-keeping
2745         final StatusBarNotification n = new StatusBarNotification(
2746                 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2747                 user);
2748         final NotificationRecord r = new NotificationRecord(getContext(), n);
2749         mHandler.post(new EnqueueNotificationRunnable(userId, r));
2750
2751         idOut[0] = id;
2752     }
2753
2754     private class EnqueueNotificationRunnable implements Runnable {
2755         private final NotificationRecord r;
2756         private final int userId;
2757
2758         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2759             this.userId = userId;
2760             this.r = r;
2761         };
2762
2763         @Override
2764         public void run() {
2765
2766             synchronized (mNotificationList) {
2767                 final StatusBarNotification n = r.sbn;
2768                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2769                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2770                 if (old != null) {
2771                     // Retain ranking information from previous record
2772                     r.copyRankingInformation(old);
2773                 }
2774
2775                 final int callingUid = n.getUid();
2776                 final int callingPid = n.getInitialPid();
2777                 final Notification notification = n.getNotification();
2778                 final String pkg = n.getPackageName();
2779                 final int id = n.getId();
2780                 final String tag = n.getTag();
2781                 final boolean isSystemNotification = isUidSystem(callingUid) ||
2782                         ("android".equals(pkg));
2783
2784                 // Handle grouped notifications and bail out early if we
2785                 // can to avoid extracting signals.
2786                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2787
2788                 // This conditional is a dirty hack to limit the logging done on
2789                 //     behalf of the download manager without affecting other apps.
2790                 if (!pkg.equals("com.android.providers.downloads")
2791                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2792                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2793                     if (old != null) {
2794                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2795                     }
2796                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2797                             pkg, id, tag, userId, notification.toString(),
2798                             enqueueStatus);
2799                 }
2800
2801                 mRankingHelper.extractSignals(r);
2802
2803                 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2804
2805                 // blocked apps
2806                 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2807                         || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2808                     if (!isSystemNotification) {
2809                         if (isPackageSuspended) {
2810                             Slog.e(TAG, "Suppressing notification from package due to package "
2811                                     + "suspended by administrator.");
2812                             mUsageStats.registerSuspendedByAdmin(r);
2813                         } else {
2814                             Slog.e(TAG, "Suppressing notification from package by user request.");
2815                             mUsageStats.registerBlocked(r);
2816                         }
2817                         return;
2818                     }
2819                 }
2820
2821                 // tell the ranker service about the notification
2822                 if (mRankerServices.isEnabled()) {
2823                     mRankerServices.onNotificationEnqueued(r);
2824                     // TODO delay the code below here for 100ms or until there is an answer
2825                 }
2826
2827
2828                 int index = indexOfNotificationLocked(n.getKey());
2829                 if (index < 0) {
2830                     mNotificationList.add(r);
2831                     mUsageStats.registerPostedByApp(r);
2832                 } else {
2833                     old = mNotificationList.get(index);
2834                     mNotificationList.set(index, r);
2835                     mUsageStats.registerUpdatedByApp(r, old);
2836                     // Make sure we don't lose the foreground service state.
2837                     notification.flags |=
2838                             old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2839                     r.isUpdate = true;
2840                 }
2841
2842                 mNotificationsByKey.put(n.getKey(), r);
2843
2844                 // Ensure if this is a foreground service that the proper additional
2845                 // flags are set.
2846                 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2847                     notification.flags |= Notification.FLAG_ONGOING_EVENT
2848                             | Notification.FLAG_NO_CLEAR;
2849                 }
2850
2851                 applyZenModeLocked(r);
2852                 mRankingHelper.sort(mNotificationList);
2853
2854                 if (notification.getSmallIcon() != null) {
2855                     StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2856                     mListeners.notifyPostedLocked(n, oldSbn);
2857                 } else {
2858                     Slog.e(TAG, "Not posting notification without small icon: " + notification);
2859                     if (old != null && !old.isCanceled) {
2860                         mListeners.notifyRemovedLocked(n);
2861                     }
2862                     // ATTENTION: in a future release we will bail out here
2863                     // so that we do not play sounds, show lights, etc. for invalid
2864                     // notifications
2865                     Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2866                             + n.getPackageName());
2867                 }
2868
2869                 buzzBeepBlinkLocked(r);
2870             }
2871         }
2872     }
2873
2874     /**
2875      * Ensures that grouped notification receive their special treatment.
2876      *
2877      * <p>Cancels group children if the new notification causes a group to lose
2878      * its summary.</p>
2879      *
2880      * <p>Updates mSummaryByGroupKey.</p>
2881      */
2882     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2883             int callingUid, int callingPid) {
2884         StatusBarNotification sbn = r.sbn;
2885         Notification n = sbn.getNotification();
2886         if (n.isGroupSummary() && !sbn.isAppGroup())  {
2887             // notifications without a group shouldn't be a summary, otherwise autobundling can
2888             // lead to bugs
2889             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2890         }
2891
2892         String group = sbn.getGroupKey();
2893         boolean isSummary = n.isGroupSummary();
2894
2895         Notification oldN = old != null ? old.sbn.getNotification() : null;
2896         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2897         boolean oldIsSummary = old != null && oldN.isGroupSummary();
2898
2899         if (oldIsSummary) {
2900             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2901             if (removedSummary != old) {
2902                 String removedKey =
2903                         removedSummary != null ? removedSummary.getKey() : "<null>";
2904                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2905                         ", removed=" + removedKey);
2906             }
2907         }
2908         if (isSummary) {
2909             mSummaryByGroupKey.put(group, r);
2910         }
2911
2912         // Clear out group children of the old notification if the update
2913         // causes the group summary to go away. This happens when the old
2914         // notification was a summary and the new one isn't, or when the old
2915         // notification was a summary and its group key changed.
2916         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2917             cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2918                     REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
2919         }
2920     }
2921
2922     @VisibleForTesting
2923     void buzzBeepBlinkLocked(NotificationRecord record) {
2924         boolean buzz = false;
2925         boolean beep = false;
2926         boolean blink = false;
2927
2928         final Notification notification = record.sbn.getNotification();
2929         final String key = record.getKey();
2930
2931         // Should this notification make noise, vibe, or use the LED?
2932         final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2933         final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2934         if (DBG || record.isIntercepted())
2935             Slog.v(TAG,
2936                     "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2937                             " intercept=" + record.isIntercepted()
2938             );
2939
2940         final int currentUser;
2941         final long token = Binder.clearCallingIdentity();
2942         try {
2943             currentUser = ActivityManager.getCurrentUser();
2944         } finally {
2945             Binder.restoreCallingIdentity(token);
2946         }
2947
2948         // If we're not supposed to beep, vibrate, etc. then don't.
2949         final String disableEffects = disableNotificationEffects(record);
2950         if (disableEffects != null) {
2951             ZenLog.traceDisableEffects(record, disableEffects);
2952         }
2953
2954         // Remember if this notification already owns the notification channels.
2955         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2956         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2957
2958         // These are set inside the conditional if the notification is allowed to make noise.
2959         boolean hasValidVibrate = false;
2960         boolean hasValidSound = false;
2961
2962         boolean smsRingtone =  false;
2963         if (mCarrierConfig == null) {
2964             mCarrierConfig = mConfigManager.getConfig();
2965         } else {
2966             smsRingtone = mCarrierConfig.getBoolean(
2967                 CarrierConfigManager.KEY_CONFIG_SMS_RINGTONE_INCALL);
2968         }
2969         if ((disableEffects == null || (smsRingtone && mInCall))
2970                 && (record.getUserId() == UserHandle.USER_ALL ||
2971                     record.getUserId() == currentUser ||
2972                     mUserProfiles.isCurrentProfile(record.getUserId()))
2973                 && canInterrupt
2974                 && mSystemReady
2975                 && mAudioManager != null) {
2976             if (DBG) Slog.v(TAG, "Interrupting!");
2977
2978             // should we use the default notification sound? (indicated either by
2979             // DEFAULT_SOUND or because notification.sound is pointing at
2980             // Settings.System.NOTIFICATION_SOUND)
2981             final boolean useDefaultSound =
2982                    (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2983                            Settings.System.DEFAULT_NOTIFICATION_URI
2984                                    .equals(notification.sound);
2985
2986             Uri soundUri = null;
2987             if (useDefaultSound) {
2988                 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2989
2990                 // check to see if the default notification sound is silent
2991                 ContentResolver resolver = getContext().getContentResolver();
2992                 hasValidSound = Settings.System.getString(resolver,
2993                        Settings.System.NOTIFICATION_SOUND) != null;
2994             } else if (notification.sound != null) {
2995                 soundUri = notification.sound;
2996                 hasValidSound = (soundUri != null);
2997             }
2998
2999             // Does the notification want to specify its own vibration?
3000             final boolean hasCustomVibrate = notification.vibrate != null;
3001
3002             // new in 4.2: if there was supposed to be a sound and we're in vibrate
3003             // mode, and no other vibration is specified, we fall back to vibration
3004             final boolean convertSoundToVibration =
3005                     !hasCustomVibrate
3006                             && hasValidSound
3007                             && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
3008
3009             // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
3010             final boolean useDefaultVibrate =
3011                     (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
3012
3013             hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
3014                     hasCustomVibrate;
3015
3016             // We can alert, and we're allowed to alert, but if the developer asked us to only do
3017             // it once, and we already have, then don't.
3018             if (!(record.isUpdate
3019                     && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
3020
3021                 sendAccessibilityEvent(notification, record.sbn.getPackageName());
3022
3023                 if (hasValidSound) {
3024                     boolean looping =
3025                             (notification.flags & Notification.FLAG_INSISTENT) != 0;
3026                     AudioAttributes audioAttributes = audioAttributesForNotification(notification);
3027                     mSoundNotificationKey = key;
3028                     // do not play notifications if stream volume is 0 (typically because
3029                     // ringer mode is silent) or if there is a user of exclusive audio focus
3030                     if ((mAudioManager.getStreamVolume(
3031                             AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
3032                             && !mAudioManager.isAudioFocusExclusive()) {
3033                         final long identity = Binder.clearCallingIdentity();
3034                         try {
3035                             final IRingtonePlayer player =
3036                                     mAudioManager.getRingtonePlayer();
3037                             if (player != null) {
3038                                 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
3039                                         + " with attributes " + audioAttributes);
3040                                 player.playAsync(soundUri, record.sbn.getUser(), looping,
3041                                         audioAttributes);
3042                                 beep = true;
3043                             }
3044                         } catch (RemoteException e) {
3045                         } finally {
3046                             Binder.restoreCallingIdentity(identity);
3047                         }
3048                     }
3049                 }
3050
3051                 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
3052                         == AudioManager.RINGER_MODE_SILENT)) {
3053                     mVibrateNotificationKey = key;
3054
3055                     if (useDefaultVibrate || convertSoundToVibration) {
3056                         // Escalate privileges so we can use the vibrator even if the
3057                         // notifying app does not have the VIBRATE permission.
3058                         long identity = Binder.clearCallingIdentity();
3059                         try {
3060                             mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3061                                     useDefaultVibrate ? mDefaultVibrationPattern
3062                                             : mFallbackVibrationPattern,
3063                                     ((notification.flags & Notification.FLAG_INSISTENT) != 0)
3064                                             ? 0: -1, audioAttributesForNotification(notification));
3065                             buzz = true;
3066                         } finally {
3067                             Binder.restoreCallingIdentity(identity);
3068                         }
3069                     } else if (notification.vibrate.length > 1) {
3070                         // If you want your own vibration pattern, you need the VIBRATE
3071                         // permission
3072                         mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3073                                 notification.vibrate,
3074                                 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
3075                                         ? 0: -1, audioAttributesForNotification(notification));
3076                         buzz = true;
3077                     }
3078                 }
3079             }
3080
3081         }
3082         // If a notification is updated to remove the actively playing sound or vibrate,
3083         // cancel that feedback now
3084         if (wasBeep && !hasValidSound) {
3085             clearSoundLocked();
3086         }
3087         if (wasBuzz && !hasValidVibrate) {
3088             clearVibrateLocked();
3089         }
3090
3091         // light
3092         // release the light
3093         boolean wasShowLights = mLights.remove(key);
3094         final boolean aboveThresholdWithLight = aboveThreshold || isLedNotificationForcedOn(record);
3095         if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThresholdWithLight
3096                 && ((record.getSuppressedVisualEffects()
3097                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
3098             mLights.add(key);
3099             updateLightsLocked();
3100             if (mUseAttentionLight) {
3101                 mAttentionLight.pulse();
3102             }
3103             blink = true;
3104         } else if (wasShowLights) {
3105             updateLightsLocked();
3106         }
3107         if (buzz || beep || blink) {
3108             if (((record.getSuppressedVisualEffects()
3109                     & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
3110                 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
3111             } else {
3112                 EventLogTags.writeNotificationAlert(key,
3113                         buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
3114                 mHandler.post(mBuzzBeepBlinked);
3115             }
3116         }
3117     }
3118
3119     private static AudioAttributes audioAttributesForNotification(Notification n) {
3120         if (n.audioAttributes != null
3121                 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
3122             // the audio attributes are set and different from the default, use them
3123             return n.audioAttributes;
3124         } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
3125             // the stream type is valid, use it
3126             return new AudioAttributes.Builder()
3127                     .setInternalLegacyStreamType(n.audioStreamType)
3128                     .build();
3129         } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
3130             return Notification.AUDIO_ATTRIBUTES_DEFAULT;
3131         } else {
3132             Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
3133             return Notification.AUDIO_ATTRIBUTES_DEFAULT;
3134         }
3135     }
3136
3137     void showNextToastLocked() {
3138         ToastRecord record = mToastQueue.get(0);
3139         while (record != null) {
3140             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3141             try {
3142                 record.callback.show();
3143                 scheduleTimeoutLocked(record);
3144                 return;
3145             } catch (RemoteException e) {
3146                 Slog.w(TAG, "Object died trying to show notification " + record.callback
3147                         + " in package " + record.pkg);
3148                 // remove it from the list and let the process die
3149                 int index = mToastQueue.indexOf(record);
3150                 if (index >= 0) {
3151                     mToastQueue.remove(index);
3152                 }
3153                 keepProcessAliveLocked(record.pid);
3154                 if (mToastQueue.size() > 0) {
3155                     record = mToastQueue.get(0);
3156                 } else {
3157                     record = null;
3158                 }
3159             }
3160         }
3161     }
3162
3163     void cancelToastLocked(int index) {
3164         ToastRecord record = mToastQueue.get(index);
3165         try {
3166             record.callback.hide();
3167         } catch (RemoteException e) {
3168             Slog.w(TAG, "Object died trying to hide notification " + record.callback
3169                     + " in package " + record.pkg);
3170             // don't worry about this, we're about to remove it from
3171             // the list anyway
3172         }
3173         mToastQueue.remove(index);
3174         keepProcessAliveLocked(record.pid);
3175         if (mToastQueue.size() > 0) {
3176             // Show the next one. If the callback fails, this will remove
3177             // it from the list, so don't assume that the list hasn't changed
3178             // after this point.
3179             showNextToastLocked();
3180         }
3181     }
3182
3183     private void scheduleTimeoutLocked(ToastRecord r)
3184     {
3185         mHandler.removeCallbacksAndMessages(r);
3186         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3187         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3188         mHandler.sendMessageDelayed(m, delay);
3189     }
3190
3191     private void handleTimeout(ToastRecord record)
3192     {
3193         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3194         synchronized (mToastQueue) {
3195             int index = indexOfToastLocked(record.pkg, record.callback);
3196             if (index >= 0) {
3197                 cancelToastLocked(index);
3198             }
3199         }
3200     }
3201
3202     // lock on mToastQueue
3203     int indexOfToastLocked(String pkg, ITransientNotification callback)
3204     {
3205         IBinder cbak = callback.asBinder();
3206         ArrayList<ToastRecord> list = mToastQueue;
3207         int len = list.size();
3208         for (int i=0; i<len; i++) {
3209             ToastRecord r = list.get(i);
3210             if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3211                 return i;
3212             }
3213         }
3214         return -1;
3215     }
3216
3217     // lock on mToastQueue
3218     void keepProcessAliveLocked(int pid)
3219     {
3220         int toastCount = 0; // toasts from this pid
3221         ArrayList<ToastRecord> list = mToastQueue;
3222         int N = list.size();
3223         for (int i=0; i<N; i++) {
3224             ToastRecord r = list.get(i);
3225             if (r.pid == pid) {
3226                 toastCount++;
3227             }
3228         }
3229         try {
3230             mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3231         } catch (RemoteException e) {
3232             // Shouldn't happen.
3233         }
3234     }
3235
3236     private void handleRankingReconsideration(Message message) {
3237         if (!(message.obj instanceof RankingReconsideration)) return;
3238         RankingReconsideration recon = (RankingReconsideration) message.obj;
3239         recon.run();
3240         boolean changed;
3241         synchronized (mNotificationList) {
3242             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3243             if (record == null) {
3244                 return;
3245             }
3246             int indexBefore = findNotificationRecordIndexLocked(record);
3247             boolean interceptBefore = record.isIntercepted();
3248             int visibilityBefore = record.getPackageVisibilityOverride();
3249             recon.applyChangesLocked(record);
3250             applyZenModeLocked(record);
3251             mRankingHelper.sort(mNotificationList);
3252             int indexAfter = findNotificationRecordIndexLocked(record);
3253             boolean interceptAfter = record.isIntercepted();
3254             int visibilityAfter = record.getPackageVisibilityOverride();
3255             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3256                     || visibilityBefore != visibilityAfter;
3257             if (interceptBefore && !interceptAfter) {
3258                 buzzBeepBlinkLocked(record);
3259             }
3260         }
3261         if (changed) {
3262             scheduleSendRankingUpdate();
3263         }
3264     }
3265
3266     private void handleRankingSort() {
3267         synchronized (mNotificationList) {
3268             final int N = mNotificationList.size();
3269             ArrayList<String> orderBefore = new ArrayList<String>(N);
3270             ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3271             int[] visibilities = new int[N];
3272             int[] importances = new int[N];
3273             for (int i = 0; i < N; i++) {
3274                 final NotificationRecord r = mNotificationList.get(i);
3275                 orderBefore.add(r.getKey());
3276                 groupOverrideBefore.add(r.sbn.getGroupKey());
3277                 visibilities[i] = r.getPackageVisibilityOverride();
3278                 importances[i] = r.getImportance();
3279                 mRankingHelper.extractSignals(r);
3280             }
3281             mRankingHelper.sort(mNotificationList);
3282             for (int i = 0; i < N; i++) {
3283                 final NotificationRecord r = mNotificationList.get(i);
3284                 if (!orderBefore.get(i).equals(r.getKey())
3285                         || visibilities[i] != r.getPackageVisibilityOverride()
3286                         || importances[i] != r.getImportance()
3287                         || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
3288                     scheduleSendRankingUpdate();
3289                     return;
3290                 }
3291             }
3292         }
3293     }
3294
3295     // let zen mode evaluate this record
3296     private void applyZenModeLocked(NotificationRecord record) {
3297         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3298         if (record.isIntercepted()) {
3299             int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3300                     ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3301                     | (mZenModeHelper.shouldSuppressWhenScreenOn()
3302                     ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3303             record.setSuppressedVisualEffects(suppressed);
3304         }
3305     }
3306
3307     // lock on mNotificationList
3308     private int findNotificationRecordIndexLocked(NotificationRecord target) {
3309         return mRankingHelper.indexOf(mNotificationList, target);
3310     }
3311
3312     private void scheduleSendRankingUpdate() {
3313         if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3314             Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3315             mHandler.sendMessage(m);
3316         }
3317     }
3318
3319     private void handleSendRankingUpdate() {
3320         synchronized (mNotificationList) {
3321             mListeners.notifyRankingUpdateLocked();
3322         }
3323     }
3324
3325     private void scheduleListenerHintsChanged(int state) {
3326         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3327         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3328     }
3329
3330     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3331         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3332         mHandler.obtainMessage(
3333                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3334                 listenerInterruptionFilter,
3335                 0).sendToTarget();
3336     }
3337
3338     private void handleListenerHintsChanged(int hints) {
3339         synchronized (mNotificationList) {
3340             mListeners.notifyListenerHintsChangedLocked(hints);
3341         }
3342     }
3343
3344     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3345         synchronized (mNotificationList) {
3346             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3347         }
3348     }
3349
3350     private final class WorkerHandler extends Handler
3351     {
3352         @Override
3353         public void handleMessage(Message msg)
3354         {
3355             switch (msg.what)
3356             {
3357                 case MESSAGE_TIMEOUT:
3358                     handleTimeout((ToastRecord)msg.obj);
3359                     break;
3360                 case MESSAGE_SAVE_POLICY_FILE:
3361                     handleSavePolicyFile();
3362                     break;
3363                 case MESSAGE_SEND_RANKING_UPDATE:
3364                     handleSendRankingUpdate();
3365                     break;
3366                 case MESSAGE_LISTENER_HINTS_CHANGED:
3367                     handleListenerHintsChanged(msg.arg1);
3368                     break;
3369                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3370                     handleListenerInterruptionFilterChanged(msg.arg1);
3371                     break;
3372             }
3373         }
3374
3375     }
3376
3377     private final class RankingHandlerWorker extends Handler implements RankingHandler
3378     {
3379         public RankingHandlerWorker(Looper looper) {
3380             super(looper);
3381         }
3382
3383         @Override
3384         public void handleMessage(Message msg) {
3385             switch (msg.what) {
3386                 case MESSAGE_RECONSIDER_RANKING:
3387                     handleRankingReconsideration(msg);
3388                     break;
3389                 case MESSAGE_RANKING_SORT:
3390                     handleRankingSort();
3391                     break;
3392             }
3393         }
3394
3395         public void requestSort() {
3396             removeMessages(MESSAGE_RANKING_SORT);
3397             sendEmptyMessage(MESSAGE_RANKING_SORT);
3398         }
3399
3400         public void requestReconsideration(RankingReconsideration recon) {
3401             Message m = Message.obtain(this,
3402                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3403             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3404             sendMessageDelayed(m, delay);
3405         }
3406     }
3407
3408     // Notifications
3409     // ============================================================================
3410     static int clamp(int x, int low, int high) {
3411         return (x < low) ? low : ((x > high) ? high : x);
3412     }
3413
3414     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3415         AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3416         if (!manager.isEnabled()) {
3417             return;
3418         }
3419
3420         AccessibilityEvent event =
3421             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3422         event.setPackageName(packageName);
3423         event.setClassName(Notification.class.getName());
3424         event.setParcelableData(notification);
3425         CharSequence tickerText = notification.tickerText;
3426         if (!TextUtils.isEmpty(tickerText)) {
3427             event.getText().add(tickerText);
3428         }
3429
3430         manager.sendAccessibilityEvent(event);
3431     }
3432
3433     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3434         // tell the app
3435         if (sendDelete) {
3436             if (r.getNotification().deleteIntent != null) {
3437                 try {
3438                     r.getNotification().deleteIntent.send();
3439                 } catch (PendingIntent.CanceledException ex) {
3440                     // do nothing - there's no relevant way to recover, and
3441                     //     no reason to let this propagate
3442                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3443                 }
3444             }
3445         }
3446
3447         // status bar
3448         if (r.getNotification().getSmallIcon() != null) {
3449             r.isCanceled = true;
3450             mListeners.notifyRemovedLocked(r.sbn);
3451         }
3452
3453         final String canceledKey = r.getKey();
3454
3455         // sound
3456         if (canceledKey.equals(mSoundNotificationKey)) {
3457             mSoundNotificationKey = null;
3458             final long identity = Binder.clearCallingIdentity();
3459             try {
3460                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3461                 if (player != null) {
3462                     player.stopAsync();
3463                 }
3464             } catch (RemoteException e) {
3465             } finally {
3466                 Binder.restoreCallingIdentity(identity);
3467             }
3468         }
3469
3470         // vibrate
3471         if (canceledKey.equals(mVibrateNotificationKey)) {
3472             mVibrateNotificationKey = null;
3473             long identity = Binder.clearCallingIdentity();
3474             try {
3475                 mVibrator.cancel();
3476             }
3477             finally {
3478                 Binder.restoreCallingIdentity(identity);
3479             }
3480         }
3481
3482         // light
3483         mLights.remove(canceledKey);
3484
3485         // Record usage stats
3486         // TODO: add unbundling stats?
3487         switch (reason) {
3488             case REASON_DELEGATE_CANCEL:
3489             case REASON_DELEGATE_CANCEL_ALL:
3490             case REASON_LISTENER_CANCEL:
3491             case REASON_LISTENER_CANCEL_ALL:
3492                 mUsageStats.registerDismissedByUser(r);
3493                 break;
3494             case REASON_APP_CANCEL:
3495             case REASON_APP_CANCEL_ALL:
3496                 mUsageStats.registerRemovedByApp(r);
3497                 break;
3498         }
3499
3500         mNotificationsByKey.remove(r.sbn.getKey());
3501         String groupKey = r.getGroupKey();
3502         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3503         if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3504             mSummaryByGroupKey.remove(groupKey);
3505         }
3506         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3507         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3508             summaries.remove(r.sbn.getPackageName());
3509         }
3510
3511         // Save it for users of getHistoricalNotifications()
3512         mArchive.record(r.sbn);
3513
3514         final long now = System.currentTimeMillis();
3515         EventLogTags.writeNotificationCanceled(canceledKey, reason,
3516                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3517     }
3518
3519     /**
3520      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3521      * and none of the {@code mustNotHaveFlags}.
3522      */
3523     void cancelNotification(final int callingUid, final int callingPid,
3524             final String pkg, final String tag, final int id,
3525             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3526             final int userId, final int reason, final ManagedServiceInfo listener) {
3527         // In enqueueNotificationInternal notifications are added by scheduling the
3528         // work on the worker handler. Hence, we also schedule the cancel on this
3529         // handler to avoid a scenario where an add notification call followed by a
3530         // remove notification call ends up in not removing the notification.
3531         mHandler.post(new Runnable() {
3532             @Override
3533             public void run() {
3534                 String listenerName = listener == null ? null : listener.component.toShortString();
3535                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3536                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3537
3538                 synchronized (mNotificationList) {
3539                     int index = indexOfNotificationLocked(pkg, tag, id, userId);
3540                     if (index >= 0) {
3541                         NotificationRecord r = mNotificationList.get(index);
3542
3543                         // Ideally we'd do this in the caller of this method. However, that would
3544                         // require the caller to also find the notification.
3545                         if (reason == REASON_DELEGATE_CLICK) {
3546                             mUsageStats.registerClickedByUser(r);
3547                         }
3548
3549                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3550                             return;
3551                         }
3552                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3553                             return;
3554                         }
3555
3556                         mNotificationList.remove(index);
3557
3558                         cancelNotificationLocked(r, sendDelete, reason);
3559                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3560                                 REASON_GROUP_SUMMARY_CANCELED, sendDelete);
3561                         updateLightsLocked();
3562                     }
3563                 }
3564             }
3565         });
3566     }
3567
3568     /**
3569      * Determine whether the userId applies to the notification in question, either because
3570      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3571      */
3572     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3573         return
3574                 // looking for USER_ALL notifications? match everything
3575                    userId == UserHandle.USER_ALL
3576                 // a notification sent to USER_ALL matches any query
3577                 || r.getUserId() == UserHandle.USER_ALL
3578                 // an exact user match
3579                 || r.getUserId() == userId;
3580     }
3581
3582     /**
3583      * Determine whether the userId applies to the notification in question, either because
3584      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3585      * because it matches one of the users profiles.
3586      */
3587     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3588         return notificationMatchesUserId(r, userId)
3589                 || mUserProfiles.isCurrentProfile(r.getUserId());
3590     }
3591
3592     /**
3593      * Cancels all notifications from a given package that have all of the
3594      * {@code mustHaveFlags}.
3595      */
3596     boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3597             int mustNotHaveFlags, boolean doit, int userId, int reason,
3598             ManagedServiceInfo listener) {
3599         String listenerName = listener == null ? null : listener.component.toShortString();
3600         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3601                 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3602                 listenerName);
3603
3604         synchronized (mNotificationList) {
3605             final int N = mNotificationList.size();
3606             ArrayList<NotificationRecord> canceledNotifications = null;
3607             for (int i = N-1; i >= 0; --i) {
3608                 NotificationRecord r = mNotificationList.get(i);
3609                 if (!notificationMatchesUserId(r, userId)) {
3610                     continue;
3611                 }
3612                 // Don't remove notifications to all, if there's no package name specified
3613                 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3614                     continue;
3615                 }
3616                 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3617                     continue;
3618                 }
3619                 if ((r.getFlags() & mustNotHaveFlags) != 0) {
3620                     continue;
3621                 }
3622                 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3623                     continue;
3624                 }
3625                 if (canceledNotifications == null) {
3626                     canceledNotifications = new ArrayList<>();
3627                 }
3628                 canceledNotifications.add(r);
3629                 if (!doit) {
3630                     return true;
3631                 }
3632                 mNotificationList.remove(i);
3633                 cancelNotificationLocked(r, false, reason);
3634             }
3635             if (doit && canceledNotifications != null) {
3636                 final int M = canceledNotifications.size();
3637                 for (int i = 0; i < M; i++) {
3638                     cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3639                             listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3640                 }
3641             }
3642             if (canceledNotifications != null) {
3643                 updateLightsLocked();
3644             }
3645             return canceledNotifications != null;
3646         }
3647     }
3648
3649     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3650             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3651         String listenerName = listener == null ? null : listener.component.toShortString();
3652         EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3653                 null, userId, 0, 0, reason, listenerName);
3654
3655         ArrayList<NotificationRecord> canceledNotifications = null;
3656         final int N = mNotificationList.size();
3657         for (int i=N-1; i>=0; i--) {
3658             NotificationRecord r = mNotificationList.get(i);
3659             if (includeCurrentProfiles) {
3660                 if (!notificationMatchesCurrentProfiles(r, userId)) {
3661                     continue;
3662                 }
3663             } else {
3664                 if (!notificationMatchesUserId(r, userId)) {
3665                     continue;
3666                 }
3667             }
3668
3669             if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3670                             | Notification.FLAG_NO_CLEAR)) == 0) {
3671                 mNotificationList.remove(i);
3672                 cancelNotificationLocked(r, true, reason);
3673                 // Make a note so we can cancel children later.
3674                 if (canceledNotifications == null) {
3675                     canceledNotifications = new ArrayList<>();
3676                 }
3677                 canceledNotifications.add(r);
3678             }
3679         }
3680         int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3681         for (int i = 0; i < M; i++) {
3682             cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3683                     listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
3684         }
3685         updateLightsLocked();
3686     }
3687
3688     // Warning: The caller is responsible for invoking updateLightsLocked().
3689     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3690             String listenerName, int reason, boolean sendDelete) {
3691         Notification n = r.getNotification();
3692         if (!n.isGroupSummary()) {
3693             return;
3694         }
3695
3696         String pkg = r.sbn.getPackageName();
3697         int userId = r.getUserId();
3698
3699         if (pkg == null) {
3700             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3701             return;
3702         }
3703
3704         final int N = mNotificationList.size();
3705         for (int i = N - 1; i >= 0; i--) {
3706             NotificationRecord childR = mNotificationList.get(i);
3707             StatusBarNotification childSbn = childR.sbn;
3708             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
3709                     childR.getGroupKey().equals(r.getGroupKey())) {
3710                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3711                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
3712                 mNotificationList.remove(i);
3713                 cancelNotificationLocked(childR, sendDelete, reason);
3714             }
3715         }
3716     }
3717
3718     private boolean isLedNotificationForcedOn(NotificationRecord r) {
3719         if (r != null) {
3720             final Notification n = r.sbn.getNotification();
3721             if (n.extras != null) {
3722                 return n.extras.getBoolean(Notification.EXTRA_FORCE_SHOW_LIGHTS, false);
3723             }
3724         }
3725         return false;
3726     }
3727
3728     // lock on mNotificationList
3729     void updateLightsLocked()
3730     {
3731         // handle notification lights
3732         NotificationRecord ledNotification = null;
3733         while (ledNotification == null && !mLights.isEmpty()) {
3734             final String owner = mLights.get(mLights.size() - 1);
3735             ledNotification = mNotificationsByKey.get(owner);
3736             if (ledNotification == null) {
3737                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3738                 mLights.remove(owner);
3739             }
3740         }
3741
3742         // Don't flash while we are in a call or screen is on
3743         // (unless Notification has EXTRA_FORCE_SHOW_LGHTS)
3744         final boolean enableLed;
3745         if (ledNotification == null) {
3746             enableLed = false;
3747         } else if (isLedNotificationForcedOn(ledNotification)) {
3748             enableLed = true;
3749         } else if (!mScreenOnEnabled && (mInCall || mScreenOn)) {
3750             enableLed = false;
3751         } else {
3752             enableLed = true;
3753         }
3754
3755         if (!enableLed) {
3756             mNotificationLight.turnOff();
3757             if (mStatusBar != null) {
3758                 mStatusBar.notificationLightOff();
3759             }
3760         } else {
3761             final Notification ledno = ledNotification.sbn.getNotification();
3762             final NotificationLedValues ledValues = getLedValuesForNotification(ledNotification);
3763             int ledARGB;
3764             int ledOnMS;
3765             int ledOffMS;
3766
3767             if (ledValues != null) {
3768                 ledARGB = ledValues.color != 0 ? ledValues.color : mDefaultNotificationColor;
3769                 ledOnMS = ledValues.onMS >= 0 ? ledValues.onMS : mDefaultNotificationLedOn;
3770                 ledOffMS = ledValues.offMS >= 0 ? ledValues.offMS : mDefaultNotificationLedOff;
3771             } else if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3772                 ledARGB = generateLedColorForNotification(ledNotification);
3773                 ledOnMS = mDefaultNotificationLedOn;
3774                 ledOffMS = mDefaultNotificationLedOff;
3775             } else {
3776                 ledARGB = ledno.ledARGB;
3777                 ledOnMS = ledno.ledOnMS;
3778                 ledOffMS = ledno.ledOffMS;
3779             }
3780
3781             // update the LEDs modes variables
3782             mNotificationLight.setModes(mNotificationLedBrightnessLevel,
3783                     mMultipleLedsEnabledSetting);
3784
3785             if (mNotificationPulseEnabled) {
3786                 // pulse repeatedly
3787                 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3788                         ledOnMS, ledOffMS);
3789             }
3790             if (mStatusBar != null) {
3791                 // let SystemUI make an independent decision
3792                 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3793             }
3794         }
3795     }
3796
3797     private void parseNotificationPulseCustomValuesString(String customLedValuesString) {
3798         if (TextUtils.isEmpty(customLedValuesString)) {
3799             return;
3800         }
3801
3802         for (String packageValuesString : customLedValuesString.split("\\|")) {
3803             String[] packageValues = packageValuesString.split("=");
3804             if (packageValues.length != 2) {
3805                 Log.e(TAG, "Error parsing custom led values for unknown package");
3806                 continue;
3807             }
3808             String packageName = packageValues[0];
3809             String[] values = packageValues[1].split(";");
3810             if (values.length != 3) {
3811                 Log.e(TAG, "Error parsing custom led values '"
3812                         + packageValues[1] + "' for " + packageName);
3813                 continue;
3814             }
3815             NotificationLedValues ledValues = new NotificationLedValues();
3816             try {
3817                 ledValues.color = Integer.parseInt(values[0]);
3818                 ledValues.onMS = Integer.parseInt(values[1]);
3819                 ledValues.offMS = Integer.parseInt(values[2]);
3820             } catch (NumberFormatException e) {
3821                 Log.e(TAG, "Error parsing custom led values '"
3822                         + packageValues[1] + "' for " + packageName);
3823                 continue;
3824             }
3825             mNotificationPulseCustomLedValues.put(packageName, ledValues);
3826         }
3827     }
3828
3829     private NotificationLedValues getLedValuesForNotification(NotificationRecord ledNotification) {
3830         final String packageName = ledNotification.sbn.getPackageName();
3831         return mNotificationPulseCustomLedValues.get(mapPackage(packageName));
3832     }
3833
3834     private int generateLedColorForNotification(NotificationRecord ledNotification) {
3835         if (!mAutoGenerateNotificationColor) {
3836             return mDefaultNotificationColor;
3837         }
3838         if (!mMultiColorNotificationLed) {
3839             return mDefaultNotificationColor;
3840         }
3841         final String packageName = ledNotification.sbn.getPackageName();
3842         final String mapping = mapPackage(packageName);
3843         int color = mDefaultNotificationColor;
3844
3845         if (mGeneratedPackageLedColors.containsKey(mapping)) {
3846             return mGeneratedPackageLedColors.get(mapping);
3847         }
3848
3849         PackageManager pm = getContext().getPackageManager();
3850         Drawable icon;
3851         try {
3852             icon = pm.getApplicationIcon(mapping);
3853         } catch (NameNotFoundException e) {
3854             Slog.e(TAG, e.getMessage(), e);
3855             return color;
3856         }
3857
3858         color = ColorUtils.generateAlertColorFromDrawable(icon);
3859         mGeneratedPackageLedColors.put(mapping, color);
3860
3861         return color;
3862     }
3863
3864     private String mapPackage(String pkg) {
3865         if (!mPackageNameMappings.containsKey(pkg)) {
3866             return pkg;
3867         }
3868         return mPackageNameMappings.get(pkg);
3869     }
3870
3871     // lock on mNotificationList
3872     int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3873     {
3874         ArrayList<NotificationRecord> list = mNotificationList;
3875         final int len = list.size();
3876         for (int i=0; i<len; i++) {
3877             NotificationRecord r = list.get(i);
3878             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3879                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3880                 return i;
3881             }
3882         }
3883         return -1;
3884     }
3885
3886     // lock on mNotificationList
3887     int indexOfNotificationLocked(String key) {
3888         final int N = mNotificationList.size();
3889         for (int i = 0; i < N; i++) {
3890             if (key.equals(mNotificationList.get(i).getKey())) {
3891                 return i;
3892             }
3893         }
3894         return -1;
3895     }
3896
3897     private void updateNotificationPulse() {
3898         synchronized (mNotificationList) {
3899             updateLightsLocked();
3900         }
3901     }
3902
3903     private static boolean isUidSystem(int uid) {
3904         final int appid = UserHandle.getAppId(uid);
3905         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3906     }
3907
3908     private static boolean isCallerSystem() {
3909         return isUidSystem(Binder.getCallingUid());
3910     }
3911
3912     private static void checkCallerIsSystem() {
3913         if (isCallerSystem()) {
3914             return;
3915         }
3916         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3917     }
3918
3919     private static void checkCallerIsSystemOrSameApp(String pkg) {
3920         if (isCallerSystem()) {
3921             return;
3922         }
3923         checkCallerIsSameApp(pkg);
3924     }
3925
3926     private static void checkCallerIsSameApp(String pkg) {
3927         final int uid = Binder.getCallingUid();
3928         try {
3929             ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3930                     pkg, 0, UserHandle.getCallingUserId());
3931             if (ai == null) {
3932                 throw new SecurityException("Unknown package " + pkg);
3933             }
3934             if (!UserHandle.isSameApp(ai.uid, uid)) {
3935                 throw new SecurityException("Calling uid " + uid + " gave package"
3936                         + pkg + " which is owned by uid " + ai.uid);
3937             }
3938         } catch (RemoteException re) {
3939             throw new SecurityException("Unknown package " + pkg + "\n" + re);
3940         }
3941     }
3942
3943     private static String callStateToString(int state) {
3944         switch (state) {
3945             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3946             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3947             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3948             default: return "CALL_STATE_UNKNOWN_" + state;
3949         }
3950     }
3951
3952     private void listenForCallState() {
3953         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3954             @Override
3955             public void onCallStateChanged(int state, String incomingNumber) {
3956                 if (mCallState == state) return;
3957                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3958                 mCallState = state;
3959             }
3960         }, PhoneStateListener.LISTEN_CALL_STATE);
3961     }
3962
3963     /**
3964      * Generates a NotificationRankingUpdate from 'sbns', considering only
3965      * notifications visible to the given listener.
3966      *
3967      * <p>Caller must hold a lock on mNotificationList.</p>
3968      */
3969     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3970         final int N = mNotificationList.size();
3971         ArrayList<String> keys = new ArrayList<String>(N);
3972         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3973         ArrayList<Integer> importance = new ArrayList<>(N);
3974         Bundle overrideGroupKeys = new Bundle();
3975         Bundle visibilityOverrides = new Bundle();
3976         Bundle suppressedVisualEffects = new Bundle();
3977         Bundle explanation = new Bundle();
3978         for (int i = 0; i < N; i++) {
3979             NotificationRecord record = mNotificationList.get(i);
3980             if (!isVisibleToListener(record.sbn, info)) {
3981                 continue;
3982             }
3983             final String key = record.sbn.getKey();
3984             keys.add(key);
3985             importance.add(record.getImportance());
3986             if (record.getImportanceExplanation() != null) {
3987                 explanation.putCharSequence(key, record.getImportanceExplanation());
3988             }
3989             if (record.isIntercepted()) {
3990                 interceptedKeys.add(key);
3991
3992             }
3993             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3994             if (record.getPackageVisibilityOverride()
3995                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3996                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3997             }
3998             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
3999         }
4000         final int M = keys.size();
4001         String[] keysAr = keys.toArray(new String[M]);
4002         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
4003         int[] importanceAr = new int[M];
4004         for (int i = 0; i < M; i++) {
4005             importanceAr[i] = importance.get(i);
4006         }
4007         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
4008                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
4009     }
4010
4011     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
4012         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
4013             return false;
4014         }
4015         // TODO: remove this for older listeners.
4016         return true;
4017     }
4018
4019     private boolean isPackageSuspendedForUser(String pkg, int uid) {
4020         int userId = UserHandle.getUserId(uid);
4021         try {
4022             return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
4023         } catch (RemoteException re) {
4024             throw new SecurityException("Could not talk to package manager service");
4025         } catch (IllegalArgumentException ex) {
4026             // Package not found.
4027             return false;
4028         }
4029     }
4030
4031     private class TrimCache {
4032         StatusBarNotification heavy;
4033         StatusBarNotification sbnClone;
4034         StatusBarNotification sbnCloneLight;
4035
4036         TrimCache(StatusBarNotification sbn) {
4037             heavy = sbn;
4038         }
4039
4040         StatusBarNotification ForListener(ManagedServiceInfo info) {
4041             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
4042                 if (sbnCloneLight == null) {
4043                     sbnCloneLight = heavy.cloneLight();
4044                 }
4045                 return sbnCloneLight;
4046             } else {
4047                 if (sbnClone == null) {
4048                     sbnClone = heavy.clone();
4049                 }
4050                 return sbnClone;
4051             }
4052         }
4053     }
4054
4055     public class NotificationRankers extends ManagedServices {
4056
4057         public NotificationRankers() {
4058             super(getContext(), mHandler, mNotificationList, mUserProfiles);
4059         }
4060
4061         @Override
4062         protected Config getConfig() {
4063             Config c = new Config();
4064             c.caption = "notification ranker service";
4065             c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
4066             c.secureSettingName = null;
4067             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
4068             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
4069             c.clientLabel = R.string.notification_ranker_binding_label;
4070             return c;
4071         }
4072
4073         @Override
4074         protected IInterface asInterface(IBinder binder) {
4075             return INotificationListener.Stub.asInterface(binder);
4076         }
4077
4078         @Override
4079         protected boolean checkType(IInterface service) {
4080             return service instanceof INotificationListener;
4081         }
4082
4083         @Override
4084         protected void onServiceAdded(ManagedServiceInfo info) {
4085             mListeners.registerGuestService(info);
4086         }
4087
4088         @Override
4089         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
4090             mListeners.unregisterService(removed.service, removed.userid);
4091         }
4092
4093         public void onNotificationEnqueued(final NotificationRecord r) {
4094             final StatusBarNotification sbn = r.sbn;
4095             TrimCache trimCache = new TrimCache(sbn);
4096
4097             // mServices is the list inside ManagedServices of all the rankers,
4098             // There should be only one, but it's a list, so while we enforce
4099             // singularity elsewhere, we keep it general here, to avoid surprises.
4100             for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
4101                 boolean sbnVisible = isVisibleToListener(sbn, info);
4102                 if (!sbnVisible) {
4103                     continue;
4104                 }
4105
4106                 final int importance = r.getImportance();
4107                 final boolean fromUser = r.isImportanceFromUser();
4108                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4109                 mHandler.post(new Runnable() {
4110                     @Override
4111                     public void run() {
4112                         notifyEnqueued(info, sbnToPost, importance, fromUser);
4113                     }
4114                 });
4115             }
4116         }
4117
4118         private void notifyEnqueued(final ManagedServiceInfo info,
4119                 final StatusBarNotification sbn, int importance, boolean fromUser) {
4120             final INotificationListener ranker = (INotificationListener) info.service;
4121             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4122             try {
4123                 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
4124             } catch (RemoteException ex) {
4125                 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
4126             }
4127         }
4128
4129         public boolean isEnabled() {
4130             return !mServices.isEmpty();
4131         }
4132
4133         @Override
4134         public void onUserSwitched(int user) {
4135             synchronized (mNotificationList) {
4136                 int i = mServices.size()-1;
4137                 while (i --> 0) {
4138                     final ManagedServiceInfo info = mServices.get(i);
4139                     unregisterService(info.service, info.userid);
4140                 }
4141             }
4142             registerRanker();
4143         }
4144
4145         @Override
4146         public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
4147             if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
4148                     + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
4149             if (mRankerServicePackageName == null) {
4150                 return;
4151             }
4152
4153             if (pkgList != null && (pkgList.length > 0)) {
4154                 for (String pkgName : pkgList) {
4155                     if (mRankerServicePackageName.equals(pkgName)) {
4156                         registerRanker();
4157                     }
4158                 }
4159             }
4160         }
4161
4162         protected void registerRanker() {
4163             // Find the updatable ranker and register it.
4164             if (mRankerServicePackageName == null) {
4165                 Slog.w(TAG, "could not start ranker service: no package specified!");
4166                 return;
4167             }
4168             Set<ComponentName> rankerComponents = queryPackageForServices(
4169                     mRankerServicePackageName, UserHandle.USER_SYSTEM);
4170             Iterator<ComponentName> iterator = rankerComponents.iterator();
4171             if (iterator.hasNext()) {
4172                 ComponentName rankerComponent = iterator.next();
4173                 if (iterator.hasNext()) {
4174                     Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
4175                 } else {
4176                     registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
4177                 }
4178             } else {
4179                 Slog.w(TAG, "could not start ranker service: none found");
4180             }
4181         }
4182     }
4183
4184     public class NotificationListeners extends ManagedServices {
4185
4186         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
4187
4188         public NotificationListeners() {
4189             super(getContext(), mHandler, mNotificationList, mUserProfiles);
4190         }
4191
4192         @Override
4193         protected Config getConfig() {
4194             Config c = new Config();
4195             c.caption = "notification listener";
4196             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
4197             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
4198             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
4199             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
4200             c.clientLabel = R.string.notification_listener_binding_label;
4201             return c;
4202         }
4203
4204         @Override
4205         protected IInterface asInterface(IBinder binder) {
4206             return INotificationListener.Stub.asInterface(binder);
4207         }
4208
4209         @Override
4210         protected boolean checkType(IInterface service) {
4211             return service instanceof INotificationListener;
4212         }
4213
4214         @Override
4215         public void onServiceAdded(ManagedServiceInfo info) {
4216             final INotificationListener listener = (INotificationListener) info.service;
4217             final NotificationRankingUpdate update;
4218             synchronized (mNotificationList) {
4219                 update = makeRankingUpdateLocked(info);
4220             }
4221             try {
4222                 listener.onListenerConnected(update);
4223             } catch (RemoteException e) {
4224                 // we tried
4225             }
4226         }
4227
4228         @Override
4229         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
4230             if (removeDisabledHints(removed)) {
4231                 updateListenerHintsLocked();
4232                 updateEffectsSuppressorLocked();
4233             }
4234             mLightTrimListeners.remove(removed);
4235         }
4236
4237         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
4238             if (trim == TRIM_LIGHT) {
4239                 mLightTrimListeners.add(info);
4240             } else {
4241                 mLightTrimListeners.remove(info);
4242             }
4243         }
4244
4245         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
4246             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
4247         }
4248
4249         /**
4250          * asynchronously notify all listeners about a new notification
4251          *
4252          * <p>
4253          * Also takes care of removing a notification that has been visible to a listener before,
4254          * but isn't anymore.
4255          */
4256         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
4257             // Lazily initialized snapshots of the notification.
4258             TrimCache trimCache = new TrimCache(sbn);
4259
4260             for (final ManagedServiceInfo info : mServices) {
4261                 boolean sbnVisible = isVisibleToListener(sbn, info);
4262                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
4263                 // This notification hasn't been and still isn't visible -> ignore.
4264                 if (!oldSbnVisible && !sbnVisible) {
4265                     continue;
4266                 }
4267                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4268
4269                 // This notification became invisible -> remove the old one.
4270                 if (oldSbnVisible && !sbnVisible) {
4271                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4272                     mHandler.post(new Runnable() {
4273                         @Override
4274                         public void run() {
4275                             notifyRemoved(info, oldSbnLightClone, update);
4276                         }
4277                     });
4278                     continue;
4279                 }
4280
4281                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4282                 mHandler.post(new Runnable() {
4283                     @Override
4284                     public void run() {
4285                         notifyPosted(info, sbnToPost, update);
4286                     }
4287                 });
4288             }
4289         }
4290
4291         /**
4292          * asynchronously notify all listeners about a removed notification
4293          */
4294         public void notifyRemovedLocked(StatusBarNotification sbn) {
4295             // make a copy in case changes are made to the underlying Notification object
4296             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4297             // notification
4298             final StatusBarNotification sbnLight = sbn.cloneLight();
4299             for (final ManagedServiceInfo info : mServices) {
4300                 if (!isVisibleToListener(sbn, info)) {
4301                     continue;
4302                 }
4303                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4304                 mHandler.post(new Runnable() {
4305                     @Override
4306                     public void run() {
4307                         notifyRemoved(info, sbnLight, update);
4308                     }
4309                 });
4310             }
4311         }
4312
4313         /**
4314          * asynchronously notify all listeners about a reordering of notifications
4315          */
4316         public void notifyRankingUpdateLocked() {
4317             for (final ManagedServiceInfo serviceInfo : mServices) {
4318                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4319                     continue;
4320                 }
4321                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
4322                 mHandler.post(new Runnable() {
4323                     @Override
4324                     public void run() {
4325                         notifyRankingUpdate(serviceInfo, update);
4326                     }
4327                 });
4328             }
4329         }
4330
4331         public void notifyListenerHintsChangedLocked(final int hints) {
4332             for (final ManagedServiceInfo serviceInfo : mServices) {
4333                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4334                     continue;
4335                 }
4336                 mHandler.post(new Runnable() {
4337                     @Override
4338                     public void run() {
4339                         notifyListenerHintsChanged(serviceInfo, hints);
4340                     }
4341                 });
4342             }
4343         }
4344
4345         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4346             for (final ManagedServiceInfo serviceInfo : mServices) {
4347                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4348                     continue;
4349                 }
4350                 mHandler.post(new Runnable() {
4351                     @Override
4352                     public void run() {
4353                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4354                     }
4355                 });
4356             }
4357         }
4358
4359         private void notifyPosted(final ManagedServiceInfo info,
4360                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
4361             final INotificationListener listener = (INotificationListener)info.service;
4362             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4363             try {
4364                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
4365             } catch (RemoteException ex) {
4366                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4367             }
4368         }
4369
4370         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
4371                 NotificationRankingUpdate rankingUpdate) {
4372             if (!info.enabledAndUserMatches(sbn.getUserId())) {
4373                 return;
4374             }
4375             final INotificationListener listener = (INotificationListener) info.service;
4376             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4377             try {
4378                 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
4379             } catch (RemoteException ex) {
4380                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
4381             }
4382         }
4383
4384         private void notifyRankingUpdate(ManagedServiceInfo info,
4385                                          NotificationRankingUpdate rankingUpdate) {
4386             final INotificationListener listener = (INotificationListener) info.service;
4387             try {
4388                 listener.onNotificationRankingUpdate(rankingUpdate);
4389             } catch (RemoteException ex) {
4390                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4391             }
4392         }
4393
4394         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
4395             final INotificationListener listener = (INotificationListener) info.service;
4396             try {
4397                 listener.onListenerHintsChanged(hints);
4398             } catch (RemoteException ex) {
4399                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
4400             }
4401         }
4402
4403         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4404                 int interruptionFilter) {
4405             final INotificationListener listener = (INotificationListener) info.service;
4406             try {
4407                 listener.onInterruptionFilterChanged(interruptionFilter);
4408             } catch (RemoteException ex) {
4409                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4410             }
4411         }
4412
4413         private boolean isListenerPackage(String packageName) {
4414             if (packageName == null) {
4415                 return false;
4416             }
4417             // TODO: clean up locking object later
4418             synchronized (mNotificationList) {
4419                 for (final ManagedServiceInfo serviceInfo : mServices) {
4420                     if (packageName.equals(serviceInfo.component.getPackageName())) {
4421                         return true;
4422                     }
4423                 }
4424             }
4425             return false;
4426         }
4427     }
4428
4429     public static final class DumpFilter {
4430         public boolean filtered = false;
4431         public String pkgFilter;
4432         public boolean zen;
4433         public long since;
4434         public boolean stats;
4435         public boolean redact = true;
4436
4437         public static DumpFilter parseFromArguments(String[] args) {
4438             final DumpFilter filter = new DumpFilter();
4439             for (int ai = 0; ai < args.length; ai++) {
4440                 final String a = args[ai];
4441                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
4442                     filter.redact = false;
4443                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4444                     if (ai < args.length-1) {
4445                         ai++;
4446                         filter.pkgFilter = args[ai].trim().toLowerCase();
4447                         if (filter.pkgFilter.isEmpty()) {
4448                             filter.pkgFilter = null;
4449                         } else {
4450                             filter.filtered = true;
4451                         }
4452                     }
4453                 } else if ("--zen".equals(a) || "zen".equals(a)) {
4454                     filter.filtered = true;
4455                     filter.zen = true;
4456                 } else if ("--stats".equals(a)) {
4457                     filter.stats = true;
4458                     if (ai < args.length-1) {
4459                         ai++;
4460                         filter.since = Long.valueOf(args[ai]);
4461                     } else {
4462                         filter.since = 0;
4463                     }
4464                 }
4465             }
4466             return filter;
4467         }
4468
4469         public boolean matches(StatusBarNotification sbn) {
4470             if (!filtered) return true;
4471             return zen ? true : sbn != null
4472                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
4473         }
4474
4475         public boolean matches(ComponentName component) {
4476             if (!filtered) return true;
4477             return zen ? true : component != null && matches(component.getPackageName());
4478         }
4479
4480         public boolean matches(String pkg) {
4481             if (!filtered) return true;
4482             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
4483         }
4484
4485         @Override
4486         public String toString() {
4487             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
4488         }
4489     }
4490
4491     /**
4492      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4493      * binder without sending large amounts of data over a oneway transaction.
4494      */
4495     private static final class StatusBarNotificationHolder
4496             extends IStatusBarNotificationHolder.Stub {
4497         private StatusBarNotification mValue;
4498
4499         public StatusBarNotificationHolder(StatusBarNotification value) {
4500             mValue = value;
4501         }
4502
4503         /** Get the held value and clear it. This function should only be called once per holder */
4504         @Override
4505         public StatusBarNotification get() {
4506             StatusBarNotification value = mValue;
4507             mValue = null;
4508             return value;
4509         }
4510     }
4511
4512     private final class PolicyAccess {
4513         private static final String SEPARATOR = ":";
4514         private final String[] PERM = {
4515             android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4516         };
4517
4518         public boolean isPackageGranted(String pkg) {
4519             return pkg != null && getGrantedPackages().contains(pkg);
4520         }
4521
4522         public void put(String pkg, boolean granted) {
4523             if (pkg == null) return;
4524             final ArraySet<String> pkgs = getGrantedPackages();
4525             boolean changed;
4526             if (granted) {
4527                 changed = pkgs.add(pkg);
4528             } else {
4529                 changed = pkgs.remove(pkg);
4530             }
4531             if (!changed) return;
4532             final String setting = TextUtils.join(SEPARATOR, pkgs);
4533             final int currentUser = ActivityManager.getCurrentUser();
4534             Settings.Secure.putStringForUser(getContext().getContentResolver(),
4535                     Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4536                     setting,
4537                     currentUser);
4538             getContext().sendBroadcastAsUser(new Intent(NotificationManager
4539                     .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4540                 .setPackage(pkg)
4541                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4542         }
4543
4544         public ArraySet<String> getGrantedPackages() {
4545             final ArraySet<String> pkgs = new ArraySet<>();
4546
4547             long identity = Binder.clearCallingIdentity();
4548             try {
4549                 final String setting = Settings.Secure.getStringForUser(
4550                         getContext().getContentResolver(),
4551                         Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4552                         ActivityManager.getCurrentUser());
4553                 if (setting != null) {
4554                     final String[] tokens = setting.split(SEPARATOR);
4555                     for (int i = 0; i < tokens.length; i++) {
4556                         String token = tokens[i];
4557                         if (token != null) {
4558                             token = token.trim();
4559                         }
4560                         if (TextUtils.isEmpty(token)) {
4561                             continue;
4562                         }
4563                         pkgs.add(token);
4564                     }
4565                 }
4566             } finally {
4567                 Binder.restoreCallingIdentity(identity);
4568             }
4569             return pkgs;
4570         }
4571
4572         public String[] getRequestingPackages() throws RemoteException {
4573             final ParceledListSlice list = AppGlobals.getPackageManager()
4574                     .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4575                             ActivityManager.getCurrentUser());
4576             final List<PackageInfo> pkgs = list.getList();
4577             if (pkgs == null || pkgs.isEmpty()) return new String[0];
4578             final int N = pkgs.size();
4579             final String[] rt = new String[N];
4580             for (int i = 0; i < N; i++) {
4581                 rt[i] = pkgs.get(i).packageName;
4582             }
4583             return rt;
4584         }
4585     }
4586 }