NotificationManagerService.java revision 32fe4c6e642ae8a2b36136e33040e12f88aa5e07
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.notification;
18
19import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
20import static android.service.notification.NotificationListenerService.TRIM_FULL;
21import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
22import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
23import static org.xmlpull.v1.XmlPullParser.END_TAG;
24import static org.xmlpull.v1.XmlPullParser.START_TAG;
25
26import android.app.ActivityManager;
27import android.app.ActivityManagerNative;
28import android.app.AppGlobals;
29import android.app.AppOpsManager;
30import android.app.IActivityManager;
31import android.app.INotificationManager;
32import android.app.ITransientNotification;
33import android.app.Notification;
34import android.app.NotificationManager;
35import android.app.PendingIntent;
36import android.app.StatusBarManager;
37import android.content.BroadcastReceiver;
38import android.content.ComponentName;
39import android.content.ContentResolver;
40import android.content.Context;
41import android.content.Intent;
42import android.content.IntentFilter;
43import android.content.pm.ApplicationInfo;
44import android.content.pm.PackageInfo;
45import android.content.pm.PackageManager;
46import android.content.pm.PackageManager.NameNotFoundException;
47import android.content.pm.ParceledListSlice;
48import android.content.res.Resources;
49import android.database.ContentObserver;
50import android.media.AudioAttributes;
51import android.media.AudioManager;
52import android.media.AudioSystem;
53import android.media.IRingtonePlayer;
54import android.net.Uri;
55import android.os.Binder;
56import android.os.Bundle;
57import android.os.Environment;
58import android.os.Handler;
59import android.os.HandlerThread;
60import android.os.IBinder;
61import android.os.IInterface;
62import android.os.Looper;
63import android.os.Message;
64import android.os.Process;
65import android.os.RemoteException;
66import android.os.UserHandle;
67import android.os.Vibrator;
68import android.provider.Settings;
69import android.service.notification.Condition;
70import android.service.notification.IConditionListener;
71import android.service.notification.IConditionProvider;
72import android.service.notification.INotificationListener;
73import android.service.notification.IStatusBarNotificationHolder;
74import android.service.notification.NotificationListenerService;
75import android.service.notification.NotificationRankingUpdate;
76import android.service.notification.StatusBarNotification;
77import android.service.notification.ZenModeConfig;
78import android.telephony.PhoneStateListener;
79import android.telephony.TelephonyManager;
80import android.text.TextUtils;
81import android.util.ArrayMap;
82import android.util.ArraySet;
83import android.util.AtomicFile;
84import android.util.Log;
85import android.util.Slog;
86import android.util.Xml;
87import android.view.accessibility.AccessibilityEvent;
88import android.view.accessibility.AccessibilityManager;
89import android.widget.Toast;
90
91import com.android.internal.R;
92import com.android.internal.util.FastXmlSerializer;
93import com.android.server.EventLogTags;
94import com.android.server.SystemService;
95import com.android.server.lights.Light;
96import com.android.server.lights.LightsManager;
97import com.android.server.notification.ManagedServices.ManagedServiceInfo;
98import com.android.server.notification.ManagedServices.UserProfiles;
99import com.android.server.statusbar.StatusBarManagerInternal;
100
101import libcore.io.IoUtils;
102
103import org.xmlpull.v1.XmlPullParser;
104import org.xmlpull.v1.XmlPullParserException;
105import org.xmlpull.v1.XmlSerializer;
106
107import java.io.File;
108import java.io.FileDescriptor;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
111import java.io.FileOutputStream;
112import java.io.IOException;
113import java.io.PrintWriter;
114import java.util.ArrayDeque;
115import java.util.ArrayList;
116import java.util.HashSet;
117import java.util.Iterator;
118import java.util.NoSuchElementException;
119import java.util.Objects;
120
121/** {@hide} */
122public class NotificationManagerService extends SystemService {
123    static final String TAG = "NotificationService";
124    static final boolean DBG = false;
125
126    static final int MAX_PACKAGE_NOTIFICATIONS = 50;
127
128    // message codes
129    static final int MESSAGE_TIMEOUT = 2;
130    static final int MESSAGE_SAVE_POLICY_FILE = 3;
131    static final int MESSAGE_RECONSIDER_RANKING = 4;
132    static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
133    static final int MESSAGE_SEND_RANKING_UPDATE = 6;
134    static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
135    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
136
137    static final int LONG_DELAY = 3500; // 3.5 seconds
138    static final int SHORT_DELAY = 2000; // 2 seconds
139
140    static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
141    static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
142
143    static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
144    static final boolean SCORE_ONGOING_HIGHER = false;
145
146    static final int JUNK_SCORE = -1000;
147    static final int NOTIFICATION_PRIORITY_MULTIPLIER = 10;
148    static final int SCORE_DISPLAY_THRESHOLD = Notification.PRIORITY_MIN * NOTIFICATION_PRIORITY_MULTIPLIER;
149
150    // Notifications with scores below this will not interrupt the user, either via LED or
151    // sound or vibration
152    static final int SCORE_INTERRUPTION_THRESHOLD =
153            Notification.PRIORITY_LOW * NOTIFICATION_PRIORITY_MULTIPLIER;
154
155    static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
156    static final boolean ENABLE_BLOCKED_TOASTS = true;
157
158    // When #matchesCallFilter is called from the ringer, wait at most
159    // 3s to resolve the contacts. This timeout is required since
160    // ContactsProvider might take a long time to start up.
161    //
162    // Return STARRED_CONTACT when the timeout is hit in order to avoid
163    // missed calls in ZEN mode "Important".
164    static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
165    static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
166            ValidateNotificationPeople.STARRED_CONTACT;
167
168    private IActivityManager mAm;
169    AudioManager mAudioManager;
170    StatusBarManagerInternal mStatusBar;
171    Vibrator mVibrator;
172
173    final IBinder mForegroundToken = new Binder();
174    private WorkerHandler mHandler;
175    private final HandlerThread mRankingThread = new HandlerThread("ranker",
176            Process.THREAD_PRIORITY_BACKGROUND);
177
178    private Light mNotificationLight;
179    Light mAttentionLight;
180    private int mDefaultNotificationColor;
181    private int mDefaultNotificationLedOn;
182
183    private int mDefaultNotificationLedOff;
184    private long[] mDefaultVibrationPattern;
185
186    private long[] mFallbackVibrationPattern;
187    private boolean mUseAttentionLight;
188    boolean mSystemReady;
189
190    private boolean mDisableNotificationEffects;
191    private int mCallState;
192    NotificationRecord mSoundNotification;
193    NotificationRecord mVibrateNotification;
194
195    private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
196    private ComponentName mEffectsSuppressor;
197    private int mListenerHints;  // right now, all hints are global
198    private int mInterruptionFilter;  // current ZEN mode as communicated to listeners
199
200    // for enabling and disabling notification pulse behavior
201    private boolean mScreenOn = true;
202    private boolean mInCall = false;
203    private boolean mNotificationPulseEnabled;
204
205    // used as a mutex for access to all active notifications & listeners
206    final ArrayList<NotificationRecord> mNotificationList =
207            new ArrayList<NotificationRecord>();
208    final ArrayMap<String, NotificationRecord> mNotificationsByKey =
209            new ArrayMap<String, NotificationRecord>();
210    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
211
212    ArrayList<String> mLights = new ArrayList<String>();
213    NotificationRecord mLedNotification;
214
215    private AppOpsManager mAppOps;
216
217    private Archive mArchive;
218
219    // Notification control database. For now just contains disabled packages.
220    private AtomicFile mPolicyFile;
221    private HashSet<String> mBlockedPackages = new HashSet<String>();
222
223    private static final int DB_VERSION = 1;
224
225    private static final String TAG_BODY = "notification-policy";
226    private static final String ATTR_VERSION = "version";
227
228    private static final String TAG_BLOCKED_PKGS = "blocked-packages";
229    private static final String TAG_PACKAGE = "package";
230    private static final String ATTR_NAME = "name";
231
232    private RankingHelper mRankingHelper;
233
234    private final UserProfiles mUserProfiles = new UserProfiles();
235    private NotificationListeners mListeners;
236    private ConditionProviders mConditionProviders;
237    private NotificationUsageStats mUsageStats;
238
239    private static final int MY_UID = Process.myUid();
240    private static final int MY_PID = Process.myPid();
241    private static final int REASON_DELEGATE_CLICK = 1;
242    private static final int REASON_DELEGATE_CANCEL = 2;
243    private static final int REASON_DELEGATE_CANCEL_ALL = 3;
244    private static final int REASON_DELEGATE_ERROR = 4;
245    private static final int REASON_PACKAGE_CHANGED = 5;
246    private static final int REASON_USER_STOPPED = 6;
247    private static final int REASON_PACKAGE_BANNED = 7;
248    private static final int REASON_NOMAN_CANCEL = 8;
249    private static final int REASON_NOMAN_CANCEL_ALL = 9;
250    private static final int REASON_LISTENER_CANCEL = 10;
251    private static final int REASON_LISTENER_CANCEL_ALL = 11;
252    private static final int REASON_GROUP_SUMMARY_CANCELED = 12;
253
254    private static class Archive {
255        final int mBufferSize;
256        final ArrayDeque<StatusBarNotification> mBuffer;
257
258        public Archive(int size) {
259            mBufferSize = size;
260            mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
261        }
262
263        public String toString() {
264            final StringBuilder sb = new StringBuilder();
265            final int N = mBuffer.size();
266            sb.append("Archive (");
267            sb.append(N);
268            sb.append(" notification");
269            sb.append((N==1)?")":"s)");
270            return sb.toString();
271        }
272
273        public void record(StatusBarNotification nr) {
274            if (mBuffer.size() == mBufferSize) {
275                mBuffer.removeFirst();
276            }
277
278            // We don't want to store the heavy bits of the notification in the archive,
279            // but other clients in the system process might be using the object, so we
280            // store a (lightened) copy.
281            mBuffer.addLast(nr.cloneLight());
282        }
283
284        public void clear() {
285            mBuffer.clear();
286        }
287
288        public Iterator<StatusBarNotification> descendingIterator() {
289            return mBuffer.descendingIterator();
290        }
291        public Iterator<StatusBarNotification> ascendingIterator() {
292            return mBuffer.iterator();
293        }
294        public Iterator<StatusBarNotification> filter(
295                final Iterator<StatusBarNotification> iter, final String pkg, final int userId) {
296            return new Iterator<StatusBarNotification>() {
297                StatusBarNotification mNext = findNext();
298
299                private StatusBarNotification findNext() {
300                    while (iter.hasNext()) {
301                        StatusBarNotification nr = iter.next();
302                        if ((pkg == null || nr.getPackageName() == pkg)
303                                && (userId == UserHandle.USER_ALL || nr.getUserId() == userId)) {
304                            return nr;
305                        }
306                    }
307                    return null;
308                }
309
310                @Override
311                public boolean hasNext() {
312                    return mNext == null;
313                }
314
315                @Override
316                public StatusBarNotification next() {
317                    StatusBarNotification next = mNext;
318                    if (next == null) {
319                        throw new NoSuchElementException();
320                    }
321                    mNext = findNext();
322                    return next;
323                }
324
325                @Override
326                public void remove() {
327                    iter.remove();
328                }
329            };
330        }
331
332        public StatusBarNotification[] getArray(int count) {
333            if (count == 0) count = mBufferSize;
334            final StatusBarNotification[] a
335                    = new StatusBarNotification[Math.min(count, mBuffer.size())];
336            Iterator<StatusBarNotification> iter = descendingIterator();
337            int i=0;
338            while (iter.hasNext() && i < count) {
339                a[i++] = iter.next();
340            }
341            return a;
342        }
343
344        public StatusBarNotification[] getArray(int count, String pkg, int userId) {
345            if (count == 0) count = mBufferSize;
346            final StatusBarNotification[] a
347                    = new StatusBarNotification[Math.min(count, mBuffer.size())];
348            Iterator<StatusBarNotification> iter = filter(descendingIterator(), pkg, userId);
349            int i=0;
350            while (iter.hasNext() && i < count) {
351                a[i++] = iter.next();
352            }
353            return a;
354        }
355
356    }
357
358    private void loadPolicyFile() {
359        synchronized(mPolicyFile) {
360            mBlockedPackages.clear();
361
362            FileInputStream infile = null;
363            try {
364                infile = mPolicyFile.openRead();
365                final XmlPullParser parser = Xml.newPullParser();
366                parser.setInput(infile, null);
367
368                int type;
369                String tag;
370                int version = DB_VERSION;
371                while ((type = parser.next()) != END_DOCUMENT) {
372                    tag = parser.getName();
373                    if (type == START_TAG) {
374                        if (TAG_BODY.equals(tag)) {
375                            version = Integer.parseInt(
376                                    parser.getAttributeValue(null, ATTR_VERSION));
377                        } else if (TAG_BLOCKED_PKGS.equals(tag)) {
378                            while ((type = parser.next()) != END_DOCUMENT) {
379                                tag = parser.getName();
380                                if (TAG_PACKAGE.equals(tag)) {
381                                    mBlockedPackages.add(
382                                            parser.getAttributeValue(null, ATTR_NAME));
383                                } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
384                                    break;
385                                }
386                            }
387                        }
388                    }
389                    mZenModeHelper.readXml(parser);
390                    mRankingHelper.readXml(parser);
391                }
392            } catch (FileNotFoundException e) {
393                // No data yet
394            } catch (IOException e) {
395                Log.wtf(TAG, "Unable to read notification policy", e);
396            } catch (NumberFormatException e) {
397                Log.wtf(TAG, "Unable to parse notification policy", e);
398            } catch (XmlPullParserException e) {
399                Log.wtf(TAG, "Unable to parse notification policy", e);
400            } finally {
401                IoUtils.closeQuietly(infile);
402            }
403        }
404    }
405
406    public void savePolicyFile() {
407        mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
408        mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
409    }
410
411    private void handleSavePolicyFile() {
412        Slog.d(TAG, "handleSavePolicyFile");
413        synchronized (mPolicyFile) {
414            final FileOutputStream stream;
415            try {
416                stream = mPolicyFile.startWrite();
417            } catch (IOException e) {
418                Slog.w(TAG, "Failed to save policy file", e);
419                return;
420            }
421
422            try {
423                final XmlSerializer out = new FastXmlSerializer();
424                out.setOutput(stream, "utf-8");
425                out.startDocument(null, true);
426                out.startTag(null, TAG_BODY);
427                out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
428                mZenModeHelper.writeXml(out);
429                mRankingHelper.writeXml(out);
430                out.endTag(null, TAG_BODY);
431                out.endDocument();
432                mPolicyFile.finishWrite(stream);
433            } catch (IOException e) {
434                Slog.w(TAG, "Failed to save policy file, restoring backup", e);
435                mPolicyFile.failWrite(stream);
436            }
437        }
438    }
439
440    /** Use this when you actually want to post a notification or toast.
441     *
442     * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
443     */
444    private boolean noteNotificationOp(String pkg, int uid) {
445        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
446                != AppOpsManager.MODE_ALLOWED) {
447            Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
448            return false;
449        }
450        return true;
451    }
452
453    private static final class ToastRecord
454    {
455        final int pid;
456        final String pkg;
457        final ITransientNotification callback;
458        int duration;
459
460        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
461        {
462            this.pid = pid;
463            this.pkg = pkg;
464            this.callback = callback;
465            this.duration = duration;
466        }
467
468        void update(int duration) {
469            this.duration = duration;
470        }
471
472        void dump(PrintWriter pw, String prefix, DumpFilter filter) {
473            if (filter != null && !filter.matches(pkg)) return;
474            pw.println(prefix + this);
475        }
476
477        @Override
478        public final String toString()
479        {
480            return "ToastRecord{"
481                + Integer.toHexString(System.identityHashCode(this))
482                + " pkg=" + pkg
483                + " callback=" + callback
484                + " duration=" + duration;
485        }
486    }
487
488    private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
489
490        @Override
491        public void onSetDisabled(int status) {
492            synchronized (mNotificationList) {
493                mDisableNotificationEffects =
494                        (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
495                if (disableNotificationEffects(null) != null) {
496                    // cancel whatever's going on
497                    long identity = Binder.clearCallingIdentity();
498                    try {
499                        final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
500                        if (player != null) {
501                            player.stopAsync();
502                        }
503                    } catch (RemoteException e) {
504                    } finally {
505                        Binder.restoreCallingIdentity(identity);
506                    }
507
508                    identity = Binder.clearCallingIdentity();
509                    try {
510                        mVibrator.cancel();
511                    } finally {
512                        Binder.restoreCallingIdentity(identity);
513                    }
514                }
515            }
516        }
517
518        @Override
519        public void onClearAll(int callingUid, int callingPid, int userId) {
520            synchronized (mNotificationList) {
521                cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
522                        /*includeCurrentProfiles*/ true);
523            }
524        }
525
526        @Override
527        public void onNotificationClick(int callingUid, int callingPid, String key) {
528            synchronized (mNotificationList) {
529                EventLogTags.writeNotificationClicked(key);
530                NotificationRecord r = mNotificationsByKey.get(key);
531                if (r == null) {
532                    Log.w(TAG, "No notification with key: " + key);
533                    return;
534                }
535                StatusBarNotification sbn = r.sbn;
536                cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
537                        sbn.getId(), Notification.FLAG_AUTO_CANCEL,
538                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
539                        REASON_DELEGATE_CLICK, null);
540            }
541        }
542
543        @Override
544        public void onNotificationClear(int callingUid, int callingPid,
545                String pkg, String tag, int id, int userId) {
546            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
547                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
548                    true, userId, REASON_DELEGATE_CANCEL, null);
549        }
550
551        @Override
552        public void onPanelRevealed() {
553            EventLogTags.writeNotificationPanelRevealed();
554            synchronized (mNotificationList) {
555                // sound
556                mSoundNotification = null;
557
558                long identity = Binder.clearCallingIdentity();
559                try {
560                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
561                    if (player != null) {
562                        player.stopAsync();
563                    }
564                } catch (RemoteException e) {
565                } finally {
566                    Binder.restoreCallingIdentity(identity);
567                }
568
569                // vibrate
570                mVibrateNotification = null;
571                identity = Binder.clearCallingIdentity();
572                try {
573                    mVibrator.cancel();
574                } finally {
575                    Binder.restoreCallingIdentity(identity);
576                }
577
578                // light
579                mLights.clear();
580                mLedNotification = null;
581                updateLightsLocked();
582            }
583        }
584
585        @Override
586        public void onPanelHidden() {
587            EventLogTags.writeNotificationPanelHidden();
588        }
589
590        @Override
591        public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
592                int uid, int initialPid, String message, int userId) {
593            Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
594                    + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
595            cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
596                    REASON_DELEGATE_ERROR, null);
597            long ident = Binder.clearCallingIdentity();
598            try {
599                ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
600                        "Bad notification posted from package " + pkg
601                        + ": " + message);
602            } catch (RemoteException e) {
603            }
604            Binder.restoreCallingIdentity(ident);
605        }
606
607        @Override
608        public void onNotificationVisibilityChanged(
609                String[] newlyVisibleKeys, String[] noLongerVisibleKeys) {
610            // Using ';' as separator since eventlogs uses ',' to separate
611            // args.
612            EventLogTags.writeNotificationVisibilityChanged(
613                    TextUtils.join(";", newlyVisibleKeys),
614                    TextUtils.join(";", noLongerVisibleKeys));
615            synchronized (mNotificationList) {
616                for (String key : newlyVisibleKeys) {
617                    NotificationRecord r = mNotificationsByKey.get(key);
618                    if (r == null) continue;
619                    r.stats.onVisibilityChanged(true);
620                }
621                // Note that we might receive this event after notifications
622                // have already left the system, e.g. after dismissing from the
623                // shade. Hence not finding notifications in
624                // mNotificationsByKey is not an exceptional condition.
625                for (String key : noLongerVisibleKeys) {
626                    NotificationRecord r = mNotificationsByKey.get(key);
627                    if (r == null) continue;
628                    r.stats.onVisibilityChanged(false);
629                }
630            }
631        }
632
633        @Override
634        public void onNotificationExpansionChanged(String key,
635                boolean userAction, boolean expanded) {
636            EventLogTags.writeNotificationExpansion(key, userAction ? 1 : 0, expanded ? 1 : 0);
637            synchronized (mNotificationList) {
638                NotificationRecord r = mNotificationsByKey.get(key);
639                if (r != null) {
640                    r.stats.onExpansionChanged(userAction, expanded);
641                }
642            }
643        }
644    };
645
646    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
647        @Override
648        public void onReceive(Context context, Intent intent) {
649            String action = intent.getAction();
650
651            boolean queryRestart = false;
652            boolean queryRemove = false;
653            boolean packageChanged = false;
654            boolean cancelNotifications = true;
655
656            if (action.equals(Intent.ACTION_PACKAGE_ADDED)
657                    || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
658                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
659                    || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
660                    || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
661                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
662                String pkgList[] = null;
663                boolean queryReplace = queryRemove &&
664                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
665                if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
666                if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
667                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
668                } else if (queryRestart) {
669                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
670                } else {
671                    Uri uri = intent.getData();
672                    if (uri == null) {
673                        return;
674                    }
675                    String pkgName = uri.getSchemeSpecificPart();
676                    if (pkgName == null) {
677                        return;
678                    }
679                    if (packageChanged) {
680                        // We cancel notifications for packages which have just been disabled
681                        try {
682                            final int enabled = getContext().getPackageManager()
683                                    .getApplicationEnabledSetting(pkgName);
684                            if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
685                                    || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
686                                cancelNotifications = false;
687                            }
688                        } catch (IllegalArgumentException e) {
689                            // Package doesn't exist; probably racing with uninstall.
690                            // cancelNotifications is already true, so nothing to do here.
691                            if (DBG) {
692                                Slog.i(TAG, "Exception trying to look up app enabled setting", e);
693                            }
694                        }
695                    }
696                    pkgList = new String[]{pkgName};
697                }
698
699                if (pkgList != null && (pkgList.length > 0)) {
700                    for (String pkgName : pkgList) {
701                        if (cancelNotifications) {
702                            cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
703                                    UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null);
704                        }
705                    }
706                }
707                mListeners.onPackagesChanged(queryReplace, pkgList);
708                mConditionProviders.onPackagesChanged(queryReplace, pkgList);
709            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
710                // Keep track of screen on/off state, but do not turn off the notification light
711                // until user passes through the lock screen or views the notification.
712                mScreenOn = true;
713            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
714                mScreenOn = false;
715            } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
716                mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
717                        .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
718                updateNotificationPulse();
719            } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
720                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
721                if (userHandle >= 0) {
722                    cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
723                            REASON_USER_STOPPED, null);
724                }
725            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
726                // turn off LED when user passes through lock screen
727                mNotificationLight.turnOff();
728                mStatusBar.notificationLightOff();
729            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
730                // reload per-user settings
731                mSettingsObserver.update(null);
732                mUserProfiles.updateCache(context);
733                // Refresh managed services
734                mConditionProviders.onUserSwitched();
735                mListeners.onUserSwitched();
736            } else if (action.equals(Intent.ACTION_USER_ADDED)) {
737                mUserProfiles.updateCache(context);
738            }
739        }
740    };
741
742    class SettingsObserver extends ContentObserver {
743        private final Uri NOTIFICATION_LIGHT_PULSE_URI
744                = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
745
746        SettingsObserver(Handler handler) {
747            super(handler);
748        }
749
750        void observe() {
751            ContentResolver resolver = getContext().getContentResolver();
752            resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
753                    false, this, UserHandle.USER_ALL);
754            update(null);
755        }
756
757        @Override public void onChange(boolean selfChange, Uri uri) {
758            update(uri);
759        }
760
761        public void update(Uri uri) {
762            ContentResolver resolver = getContext().getContentResolver();
763            if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
764                boolean pulseEnabled = Settings.System.getInt(resolver,
765                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
766                if (mNotificationPulseEnabled != pulseEnabled) {
767                    mNotificationPulseEnabled = pulseEnabled;
768                    updateNotificationPulse();
769                }
770            }
771        }
772    }
773
774    private SettingsObserver mSettingsObserver;
775    private ZenModeHelper mZenModeHelper;
776
777    private final Runnable mBuzzBeepBlinked = new Runnable() {
778        @Override
779        public void run() {
780            mStatusBar.buzzBeepBlinked();
781        }
782    };
783
784    static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
785        int[] ar = r.getIntArray(resid);
786        if (ar == null) {
787            return def;
788        }
789        final int len = ar.length > maxlen ? maxlen : ar.length;
790        long[] out = new long[len];
791        for (int i=0; i<len; i++) {
792            out[i] = ar[i];
793        }
794        return out;
795    }
796
797    public NotificationManagerService(Context context) {
798        super(context);
799    }
800
801    @Override
802    public void onStart() {
803        Resources resources = getContext().getResources();
804
805        mAm = ActivityManagerNative.getDefault();
806        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
807        mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
808
809        mHandler = new WorkerHandler();
810        mRankingThread.start();
811        String[] extractorNames;
812        try {
813            extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
814        } catch (Resources.NotFoundException e) {
815            extractorNames = new String[0];
816        }
817        mRankingHelper = new RankingHelper(getContext(),
818                new RankingWorkerHandler(mRankingThread.getLooper()),
819                extractorNames);
820        mZenModeHelper = new ZenModeHelper(getContext(), mHandler);
821        mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
822            @Override
823            public void onConfigChanged() {
824                savePolicyFile();
825            }
826
827            @Override
828            void onZenModeChanged() {
829                synchronized(mNotificationList) {
830                    updateInterruptionFilterLocked();
831                }
832            }
833        });
834        final File systemDir = new File(Environment.getDataDirectory(), "system");
835        mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
836        mUsageStats = new NotificationUsageStats(getContext());
837
838        importOldBlockDb();
839
840        mListeners = new NotificationListeners();
841        mConditionProviders = new ConditionProviders(getContext(),
842                mHandler, mUserProfiles, mZenModeHelper);
843        mStatusBar = getLocalService(StatusBarManagerInternal.class);
844        mStatusBar.setNotificationDelegate(mNotificationDelegate);
845
846        final LightsManager lights = getLocalService(LightsManager.class);
847        mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
848        mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
849
850        mDefaultNotificationColor = resources.getColor(
851                R.color.config_defaultNotificationColor);
852        mDefaultNotificationLedOn = resources.getInteger(
853                R.integer.config_defaultNotificationLedOn);
854        mDefaultNotificationLedOff = resources.getInteger(
855                R.integer.config_defaultNotificationLedOff);
856
857        mDefaultVibrationPattern = getLongArray(resources,
858                R.array.config_defaultNotificationVibePattern,
859                VIBRATE_PATTERN_MAXLEN,
860                DEFAULT_VIBRATE_PATTERN);
861
862        mFallbackVibrationPattern = getLongArray(resources,
863                R.array.config_notificationFallbackVibePattern,
864                VIBRATE_PATTERN_MAXLEN,
865                DEFAULT_VIBRATE_PATTERN);
866
867        mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
868
869        // Don't start allowing notifications until the setup wizard has run once.
870        // After that, including subsequent boots, init with notifications turned on.
871        // This works on the first boot because the setup wizard will toggle this
872        // flag at least once and we'll go back to 0 after that.
873        if (0 == Settings.Global.getInt(getContext().getContentResolver(),
874                    Settings.Global.DEVICE_PROVISIONED, 0)) {
875            mDisableNotificationEffects = true;
876        }
877        mZenModeHelper.updateZenMode();
878
879        mUserProfiles.updateCache(getContext());
880        listenForCallState();
881
882        // register for various Intents
883        IntentFilter filter = new IntentFilter();
884        filter.addAction(Intent.ACTION_SCREEN_ON);
885        filter.addAction(Intent.ACTION_SCREEN_OFF);
886        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
887        filter.addAction(Intent.ACTION_USER_PRESENT);
888        filter.addAction(Intent.ACTION_USER_STOPPED);
889        filter.addAction(Intent.ACTION_USER_SWITCHED);
890        filter.addAction(Intent.ACTION_USER_ADDED);
891        getContext().registerReceiver(mIntentReceiver, filter);
892        IntentFilter pkgFilter = new IntentFilter();
893        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
894        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
895        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
896        pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
897        pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
898        pkgFilter.addDataScheme("package");
899        getContext().registerReceiver(mIntentReceiver, pkgFilter);
900        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
901        getContext().registerReceiver(mIntentReceiver, sdFilter);
902
903        mSettingsObserver = new SettingsObserver(mHandler);
904
905        mArchive = new Archive(resources.getInteger(
906                R.integer.config_notificationServiceArchiveSize));
907
908        publishBinderService(Context.NOTIFICATION_SERVICE, mService);
909        publishLocalService(NotificationManagerInternal.class, mInternalService);
910    }
911
912    /**
913     * Read the old XML-based app block database and import those blockages into the AppOps system.
914     */
915    private void importOldBlockDb() {
916        loadPolicyFile();
917
918        PackageManager pm = getContext().getPackageManager();
919        for (String pkg : mBlockedPackages) {
920            PackageInfo info = null;
921            try {
922                info = pm.getPackageInfo(pkg, 0);
923                setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
924            } catch (NameNotFoundException e) {
925                // forget you
926            }
927        }
928        mBlockedPackages.clear();
929    }
930
931    @Override
932    public void onBootPhase(int phase) {
933        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
934            // no beeping until we're basically done booting
935            mSystemReady = true;
936
937            // Grab our optional AudioService
938            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
939            mZenModeHelper.setAudioManager(mAudioManager);
940        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
941            // This observer will force an update when observe is called, causing us to
942            // bind to listener services.
943            mSettingsObserver.observe();
944            mListeners.onBootPhaseAppsCanStart();
945            mConditionProviders.onBootPhaseAppsCanStart();
946        }
947    }
948
949    void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
950        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
951
952        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
953                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
954
955        // Now, cancel any outstanding notifications that are part of a just-disabled app
956        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
957            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
958                    REASON_PACKAGE_BANNED, null);
959        }
960    }
961
962    private void updateListenerHintsLocked() {
963        final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
964        if (hints == mListenerHints) return;
965        mListenerHints = hints;
966        scheduleListenerHintsChanged(hints);
967    }
968
969    private void updateEffectsSuppressorLocked() {
970        final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
971                ? mListenersDisablingEffects.valueAt(0).component : null;
972        if (Objects.equals(suppressor, mEffectsSuppressor)) return;
973        mEffectsSuppressor = suppressor;
974        getContext().sendBroadcast(new Intent(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)
975                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
976    }
977
978    private void updateInterruptionFilterLocked() {
979        int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
980        if (interruptionFilter == mInterruptionFilter) return;
981        mInterruptionFilter = interruptionFilter;
982        scheduleInterruptionFilterChanged(interruptionFilter);
983    }
984
985    private final IBinder mService = new INotificationManager.Stub() {
986        // Toasts
987        // ============================================================================
988
989        @Override
990        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
991        {
992            if (DBG) {
993                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
994                        + " duration=" + duration);
995            }
996
997            if (pkg == null || callback == null) {
998                Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
999                return ;
1000            }
1001
1002            final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1003
1004            if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {
1005                if (!isSystemToast) {
1006                    Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");
1007                    return;
1008                }
1009            }
1010
1011            synchronized (mToastQueue) {
1012                int callingPid = Binder.getCallingPid();
1013                long callingId = Binder.clearCallingIdentity();
1014                try {
1015                    ToastRecord record;
1016                    int index = indexOfToastLocked(pkg, callback);
1017                    // If it's already in the queue, we update it in place, we don't
1018                    // move it to the end of the queue.
1019                    if (index >= 0) {
1020                        record = mToastQueue.get(index);
1021                        record.update(duration);
1022                    } else {
1023                        // Limit the number of toasts that any given package except the android
1024                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
1025                        if (!isSystemToast) {
1026                            int count = 0;
1027                            final int N = mToastQueue.size();
1028                            for (int i=0; i<N; i++) {
1029                                 final ToastRecord r = mToastQueue.get(i);
1030                                 if (r.pkg.equals(pkg)) {
1031                                     count++;
1032                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1033                                         Slog.e(TAG, "Package has already posted " + count
1034                                                + " toasts. Not showing more. Package=" + pkg);
1035                                         return;
1036                                     }
1037                                 }
1038                            }
1039                        }
1040
1041                        record = new ToastRecord(callingPid, pkg, callback, duration);
1042                        mToastQueue.add(record);
1043                        index = mToastQueue.size() - 1;
1044                        keepProcessAliveLocked(callingPid);
1045                    }
1046                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
1047                    // new or just been updated.  Call back and tell it to show itself.
1048                    // If the callback fails, this will remove it from the list, so don't
1049                    // assume that it's valid after this.
1050                    if (index == 0) {
1051                        showNextToastLocked();
1052                    }
1053                } finally {
1054                    Binder.restoreCallingIdentity(callingId);
1055                }
1056            }
1057        }
1058
1059        @Override
1060        public void cancelToast(String pkg, ITransientNotification callback) {
1061            Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1062
1063            if (pkg == null || callback == null) {
1064                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1065                return ;
1066            }
1067
1068            synchronized (mToastQueue) {
1069                long callingId = Binder.clearCallingIdentity();
1070                try {
1071                    int index = indexOfToastLocked(pkg, callback);
1072                    if (index >= 0) {
1073                        cancelToastLocked(index);
1074                    } else {
1075                        Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1076                                + " callback=" + callback);
1077                    }
1078                } finally {
1079                    Binder.restoreCallingIdentity(callingId);
1080                }
1081            }
1082        }
1083
1084        @Override
1085        public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1086                Notification notification, int[] idOut, int userId) throws RemoteException {
1087            enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1088                    Binder.getCallingPid(), tag, id, notification, idOut, userId);
1089        }
1090
1091        @Override
1092        public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1093            checkCallerIsSystemOrSameApp(pkg);
1094            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1095                    Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1096            // Don't allow client applications to cancel foreground service notis.
1097            cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1098                    Binder.getCallingUid() == Process.SYSTEM_UID
1099                    ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL,
1100                    null);
1101        }
1102
1103        @Override
1104        public void cancelAllNotifications(String pkg, int userId) {
1105            checkCallerIsSystemOrSameApp(pkg);
1106
1107            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1108                    Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1109
1110            // Calling from user space, don't allow the canceling of actively
1111            // running foreground services.
1112            cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1113                    pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1114                    REASON_NOMAN_CANCEL_ALL, null);
1115        }
1116
1117        @Override
1118        public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1119            checkCallerIsSystem();
1120
1121            setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1122        }
1123
1124        /**
1125         * Use this when you just want to know if notifications are OK for this package.
1126         */
1127        @Override
1128        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1129            checkCallerIsSystem();
1130            return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1131                    == AppOpsManager.MODE_ALLOWED);
1132        }
1133
1134        @Override
1135        public void setPackagePriority(String pkg, int uid, int priority) {
1136            checkCallerIsSystem();
1137            mRankingHelper.setPackagePriority(pkg, uid, priority);
1138            savePolicyFile();
1139        }
1140
1141        @Override
1142        public int getPackagePriority(String pkg, int uid) {
1143            checkCallerIsSystem();
1144            return mRankingHelper.getPackagePriority(pkg, uid);
1145        }
1146
1147        @Override
1148        public void setPackageVisibilityOverride(String pkg, int uid, int visibility) {
1149            checkCallerIsSystem();
1150            mRankingHelper.setPackageVisibilityOverride(pkg, uid, visibility);
1151            savePolicyFile();
1152        }
1153
1154        @Override
1155        public int getPackageVisibilityOverride(String pkg, int uid) {
1156            checkCallerIsSystem();
1157            return mRankingHelper.getPackageVisibilityOverride(pkg, uid);
1158        }
1159
1160        /**
1161         * System-only API for getting a list of current (i.e. not cleared) notifications.
1162         *
1163         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1164         * @returns A list of all the notifications, in natural order.
1165         */
1166        @Override
1167        public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1168            // enforce() will ensure the calling uid has the correct permission
1169            getContext().enforceCallingOrSelfPermission(
1170                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1171                    "NotificationManagerService.getActiveNotifications");
1172
1173            StatusBarNotification[] tmp = null;
1174            int uid = Binder.getCallingUid();
1175
1176            // noteOp will check to make sure the callingPkg matches the uid
1177            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1178                    == AppOpsManager.MODE_ALLOWED) {
1179                synchronized (mNotificationList) {
1180                    tmp = new StatusBarNotification[mNotificationList.size()];
1181                    final int N = mNotificationList.size();
1182                    for (int i=0; i<N; i++) {
1183                        tmp[i] = mNotificationList.get(i).sbn;
1184                    }
1185                }
1186            }
1187            return tmp;
1188        }
1189
1190        /**
1191         * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1192         *
1193         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1194         */
1195        @Override
1196        public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1197            // enforce() will ensure the calling uid has the correct permission
1198            getContext().enforceCallingOrSelfPermission(
1199                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1200                    "NotificationManagerService.getHistoricalNotifications");
1201
1202            StatusBarNotification[] tmp = null;
1203            int uid = Binder.getCallingUid();
1204
1205            // noteOp will check to make sure the callingPkg matches the uid
1206            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1207                    == AppOpsManager.MODE_ALLOWED) {
1208                synchronized (mArchive) {
1209                    tmp = mArchive.getArray(count);
1210                }
1211            }
1212            return tmp;
1213        }
1214
1215        /**
1216         * Register a listener binder directly with the notification manager.
1217         *
1218         * Only works with system callers. Apps should extend
1219         * {@link android.service.notification.NotificationListenerService}.
1220         */
1221        @Override
1222        public void registerListener(final INotificationListener listener,
1223                final ComponentName component, final int userid) {
1224            enforceSystemOrSystemUI("INotificationManager.registerListener");
1225            mListeners.registerService(listener, component, userid);
1226        }
1227
1228        /**
1229         * Remove a listener binder directly
1230         */
1231        @Override
1232        public void unregisterListener(INotificationListener listener, int userid) {
1233            mListeners.unregisterService(listener, userid);
1234        }
1235
1236        /**
1237         * Allow an INotificationListener to simulate a "clear all" operation.
1238         *
1239         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1240         *
1241         * @param token The binder for the listener, to check that the caller is allowed
1242         */
1243        @Override
1244        public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1245            final int callingUid = Binder.getCallingUid();
1246            final int callingPid = Binder.getCallingPid();
1247            long identity = Binder.clearCallingIdentity();
1248            try {
1249                synchronized (mNotificationList) {
1250                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1251                    if (keys != null) {
1252                        final int N = keys.length;
1253                        for (int i = 0; i < N; i++) {
1254                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
1255                            if (r == null) continue;
1256                            final int userId = r.sbn.getUserId();
1257                            if (userId != info.userid && userId != UserHandle.USER_ALL &&
1258                                    !mUserProfiles.isCurrentProfile(userId)) {
1259                                throw new SecurityException("Disallowed call from listener: "
1260                                        + info.service);
1261                            }
1262                            cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1263                                    r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1264                                    userId);
1265                        }
1266                    } else {
1267                        cancelAllLocked(callingUid, callingPid, info.userid,
1268                                REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
1269                    }
1270                }
1271            } finally {
1272                Binder.restoreCallingIdentity(identity);
1273            }
1274        }
1275
1276        private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
1277                int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
1278            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1279                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1280                    true,
1281                    userId, REASON_LISTENER_CANCEL, info);
1282        }
1283
1284        /**
1285         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1286         *
1287         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1288         *
1289         * @param token The binder for the listener, to check that the caller is allowed
1290         */
1291        @Override
1292        public void cancelNotificationFromListener(INotificationListener token, String pkg,
1293                String tag, int id) {
1294            final int callingUid = Binder.getCallingUid();
1295            final int callingPid = Binder.getCallingPid();
1296            long identity = Binder.clearCallingIdentity();
1297            try {
1298                synchronized (mNotificationList) {
1299                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1300                    if (info.supportsProfiles()) {
1301                        Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1302                                + "from " + info.component
1303                                + " use cancelNotification(key) instead.");
1304                    } else {
1305                        cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1306                                pkg, tag, id, info.userid);
1307                    }
1308                }
1309            } finally {
1310                Binder.restoreCallingIdentity(identity);
1311            }
1312        }
1313
1314        /**
1315         * Allow an INotificationListener to request the list of outstanding notifications seen by
1316         * the current user. Useful when starting up, after which point the listener callbacks
1317         * should be used.
1318         *
1319         * @param token The binder for the listener, to check that the caller is allowed
1320         * @param keys An array of notification keys to fetch, or null to fetch everything
1321         * @returns The return value will contain the notifications specified in keys, in that
1322         *      order, or if keys is null, all the notifications, in natural order.
1323         */
1324        @Override
1325        public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
1326                INotificationListener token, String[] keys, int trim) {
1327            synchronized (mNotificationList) {
1328                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1329                final boolean getKeys = keys != null;
1330                final int N = getKeys ? keys.length : mNotificationList.size();
1331                final ArrayList<StatusBarNotification> list
1332                        = new ArrayList<StatusBarNotification>(N);
1333                for (int i=0; i<N; i++) {
1334                    final NotificationRecord r = getKeys
1335                            ? mNotificationsByKey.get(keys[i])
1336                            : mNotificationList.get(i);
1337                    if (r == null) continue;
1338                    StatusBarNotification sbn = r.sbn;
1339                    if (!isVisibleToListener(sbn, info)) continue;
1340                    StatusBarNotification sbnToSend =
1341                            (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1342                    list.add(sbnToSend);
1343                }
1344                return new ParceledListSlice<StatusBarNotification>(list);
1345            }
1346        }
1347
1348        @Override
1349        public void requestHintsFromListener(INotificationListener token, int hints) {
1350            final long identity = Binder.clearCallingIdentity();
1351            try {
1352                synchronized (mNotificationList) {
1353                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1354                    final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0;
1355                    if (disableEffects) {
1356                        mListenersDisablingEffects.add(info);
1357                    } else {
1358                        mListenersDisablingEffects.remove(info);
1359                    }
1360                    updateListenerHintsLocked();
1361                    updateEffectsSuppressorLocked();
1362                }
1363            } finally {
1364                Binder.restoreCallingIdentity(identity);
1365            }
1366        }
1367
1368        @Override
1369        public int getHintsFromListener(INotificationListener token) {
1370            synchronized (mNotificationList) {
1371                return mListenerHints;
1372            }
1373        }
1374
1375        @Override
1376        public void requestInterruptionFilterFromListener(INotificationListener token,
1377                int interruptionFilter) throws RemoteException {
1378            final long identity = Binder.clearCallingIdentity();
1379            try {
1380                synchronized (mNotificationList) {
1381                    mListeners.checkServiceTokenLocked(token);
1382                    mZenModeHelper.requestFromListener(interruptionFilter);
1383                    updateInterruptionFilterLocked();
1384                }
1385            } finally {
1386                Binder.restoreCallingIdentity(identity);
1387            }
1388        }
1389
1390        @Override
1391        public int getInterruptionFilterFromListener(INotificationListener token)
1392                throws RemoteException {
1393            synchronized (mNotificationLight) {
1394                return mInterruptionFilter;
1395            }
1396        }
1397
1398        @Override
1399        public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1400                throws RemoteException {
1401            synchronized (mNotificationList) {
1402                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1403                if (info == null) return;
1404                mListeners.setOnNotificationPostedTrimLocked(info, trim);
1405            }
1406        }
1407
1408        @Override
1409        public ZenModeConfig getZenModeConfig() {
1410            enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
1411            return mZenModeHelper.getConfig();
1412        }
1413
1414        @Override
1415        public boolean setZenModeConfig(ZenModeConfig config) {
1416            checkCallerIsSystem();
1417            return mZenModeHelper.setConfig(config);
1418        }
1419
1420        @Override
1421        public void notifyConditions(String pkg, IConditionProvider provider,
1422                Condition[] conditions) {
1423            final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1424            checkCallerIsSystemOrSameApp(pkg);
1425            final long identity = Binder.clearCallingIdentity();
1426            try {
1427                mConditionProviders.notifyConditions(pkg, info, conditions);
1428            } finally {
1429                Binder.restoreCallingIdentity(identity);
1430            }
1431        }
1432
1433        @Override
1434        public void requestZenModeConditions(IConditionListener callback, int relevance) {
1435            enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
1436            mConditionProviders.requestZenModeConditions(callback, relevance);
1437        }
1438
1439        @Override
1440        public void setZenModeCondition(Condition condition) {
1441            enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
1442            final long identity = Binder.clearCallingIdentity();
1443            try {
1444                mConditionProviders.setZenModeCondition(condition, "binderCall");
1445            } finally {
1446                Binder.restoreCallingIdentity(identity);
1447            }
1448        }
1449
1450        @Override
1451        public void setAutomaticZenModeConditions(Uri[] conditionIds) {
1452            enforceSystemOrSystemUI("INotificationManager.setAutomaticZenModeConditions");
1453            mConditionProviders.setAutomaticZenModeConditions(conditionIds);
1454        }
1455
1456        @Override
1457        public Condition[] getAutomaticZenModeConditions() {
1458            enforceSystemOrSystemUI("INotificationManager.getAutomaticZenModeConditions");
1459            return mConditionProviders.getAutomaticZenModeConditions();
1460        }
1461
1462        private void enforceSystemOrSystemUI(String message) {
1463            if (isCallerSystem()) return;
1464            getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1465                    message);
1466        }
1467
1468        @Override
1469        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1470            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1471                    != PackageManager.PERMISSION_GRANTED) {
1472                pw.println("Permission Denial: can't dump NotificationManager from pid="
1473                        + Binder.getCallingPid()
1474                        + ", uid=" + Binder.getCallingUid());
1475                return;
1476            }
1477
1478            dumpImpl(pw, DumpFilter.parseFromArguments(args));
1479        }
1480
1481        @Override
1482        public ComponentName getEffectsSuppressor() {
1483            enforceSystemOrSystemUI("INotificationManager.getEffectsSuppressor");
1484            return mEffectsSuppressor;
1485        }
1486
1487        @Override
1488        public boolean matchesCallFilter(Bundle extras) {
1489            enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
1490            return mZenModeHelper.matchesCallFilter(
1491                    UserHandle.getCallingUserHandle(),
1492                    extras,
1493                    mRankingHelper.findExtractor(ValidateNotificationPeople.class),
1494                    MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
1495                    MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
1496        }
1497    };
1498
1499    private String[] getActiveNotificationKeys(INotificationListener token) {
1500        final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1501        final ArrayList<String> keys = new ArrayList<String>();
1502        if (info.isEnabledForCurrentProfiles()) {
1503            synchronized (mNotificationList) {
1504                final int N = mNotificationList.size();
1505                for (int i = 0; i < N; i++) {
1506                    final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1507                    if (info.enabledAndUserMatches(sbn.getUserId())) {
1508                        keys.add(sbn.getKey());
1509                    }
1510                }
1511            }
1512        }
1513        return keys.toArray(new String[keys.size()]);
1514    }
1515
1516    private String disableNotificationEffects(NotificationRecord record) {
1517        if (mDisableNotificationEffects) {
1518            return "booleanState";
1519        }
1520        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1521            return "listenerHints";
1522        }
1523        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
1524            return "callState";
1525        }
1526        return null;
1527    }
1528
1529    void dumpImpl(PrintWriter pw, DumpFilter filter) {
1530        pw.print("Current Notification Manager state");
1531        if (filter != null) {
1532            pw.print(" (filtered to "); pw.print(filter); pw.print(")");
1533        }
1534        pw.println(':');
1535        int N;
1536        final boolean zenOnly = filter != null && filter.zen;
1537
1538        if (!zenOnly) {
1539            synchronized (mToastQueue) {
1540                N = mToastQueue.size();
1541                if (N > 0) {
1542                    pw.println("  Toast Queue:");
1543                    for (int i=0; i<N; i++) {
1544                        mToastQueue.get(i).dump(pw, "    ", filter);
1545                    }
1546                    pw.println("  ");
1547                }
1548            }
1549        }
1550
1551        synchronized (mNotificationList) {
1552            if (!zenOnly) {
1553                N = mNotificationList.size();
1554                if (N > 0) {
1555                    pw.println("  Notification List:");
1556                    for (int i=0; i<N; i++) {
1557                        final NotificationRecord nr = mNotificationList.get(i);
1558                        if (filter != null && !filter.matches(nr.sbn)) continue;
1559                        nr.dump(pw, "    ", getContext());
1560                    }
1561                    pw.println("  ");
1562                }
1563
1564                if (filter == null) {
1565                    N = mLights.size();
1566                    if (N > 0) {
1567                        pw.println("  Lights List:");
1568                        for (int i=0; i<N; i++) {
1569                            pw.println("    " + mLights.get(i));
1570                        }
1571                        pw.println("  ");
1572                    }
1573                    pw.println("  mUseAttentionLight=" + mUseAttentionLight);
1574                    pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
1575                    pw.println("  mSoundNotification=" + mSoundNotification);
1576                    pw.println("  mVibrateNotification=" + mVibrateNotification);
1577                    pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
1578                    pw.println("  mCallState=" + callStateToString(mCallState));
1579                    pw.println("  mSystemReady=" + mSystemReady);
1580                }
1581                pw.println("  mArchive=" + mArchive.toString());
1582                Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
1583                int i=0;
1584                while (iter.hasNext()) {
1585                    final StatusBarNotification sbn = iter.next();
1586                    if (filter != null && !filter.matches(sbn)) continue;
1587                    pw.println("    " + sbn);
1588                    if (++i >= 5) {
1589                        if (iter.hasNext()) pw.println("    ...");
1590                        break;
1591                    }
1592                }
1593            }
1594
1595            if (!zenOnly) {
1596                pw.println("\n  Usage Stats:");
1597                mUsageStats.dump(pw, "    ", filter);
1598            }
1599
1600            if (filter == null || zenOnly) {
1601                pw.println("\n  Zen Mode:");
1602                mZenModeHelper.dump(pw, "    ");
1603
1604                pw.println("\n  Zen Log:");
1605                ZenLog.dump(pw, "    ");
1606            }
1607
1608            if (!zenOnly) {
1609                pw.println("\n  Ranking Config:");
1610                mRankingHelper.dump(pw, "    ", filter);
1611
1612                pw.println("\n  Notification listeners:");
1613                mListeners.dump(pw, filter);
1614                pw.print("    mListenerHints: "); pw.println(mListenerHints);
1615                pw.print("    mListenersDisablingEffects: (");
1616                N = mListenersDisablingEffects.size();
1617                for (int i = 0; i < N; i++) {
1618                    final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i);
1619                    if (i > 0) pw.print(',');
1620                    pw.print(listener.component);
1621                }
1622                pw.println(')');
1623            }
1624
1625            pw.println("\n  Condition providers:");
1626            mConditionProviders.dump(pw, filter);
1627        }
1628    }
1629
1630    /**
1631     * The private API only accessible to the system process.
1632     */
1633    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
1634        @Override
1635        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
1636                String tag, int id, Notification notification, int[] idReceived, int userId) {
1637            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
1638                    idReceived, userId);
1639        }
1640
1641        @Override
1642        public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
1643                int userId) {
1644            checkCallerIsSystem();
1645            synchronized (mNotificationList) {
1646                int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
1647                if (i < 0) {
1648                    Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
1649                            + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
1650                    return;
1651                }
1652                NotificationRecord r = mNotificationList.get(i);
1653                StatusBarNotification sbn = r.sbn;
1654                // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
1655                // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
1656                // we have to revert to the flags we received initially *and* force remove
1657                // FLAG_FOREGROUND_SERVICE.
1658                sbn.getNotification().flags =
1659                        (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
1660                mRankingHelper.sort(mNotificationList);
1661                mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
1662            }
1663        }
1664    };
1665
1666    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
1667            final int callingPid, final String tag, final int id, final Notification notification,
1668            int[] idOut, int incomingUserId) {
1669        if (DBG) {
1670            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
1671                    + " notification=" + notification);
1672        }
1673        checkCallerIsSystemOrSameApp(pkg);
1674        final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
1675        final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
1676
1677        final int userId = ActivityManager.handleIncomingUser(callingPid,
1678                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
1679        final UserHandle user = new UserHandle(userId);
1680
1681        // Limit the number of notifications that any given package except the android
1682        // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
1683        if (!isSystemNotification && !isNotificationFromListener) {
1684            synchronized (mNotificationList) {
1685                int count = 0;
1686                final int N = mNotificationList.size();
1687                for (int i=0; i<N; i++) {
1688                    final NotificationRecord r = mNotificationList.get(i);
1689                    if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
1690                        count++;
1691                        if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1692                            Slog.e(TAG, "Package has already posted " + count
1693                                    + " notifications.  Not showing more.  package=" + pkg);
1694                            return;
1695                        }
1696                    }
1697                }
1698            }
1699        }
1700
1701        // This conditional is a dirty hack to limit the logging done on
1702        //     behalf of the download manager without affecting other apps.
1703        if (!pkg.equals("com.android.providers.downloads")
1704                || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
1705            EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
1706                    pkg, id, tag, userId, notification.toString());
1707        }
1708
1709        if (pkg == null || notification == null) {
1710            throw new IllegalArgumentException("null not allowed: pkg=" + pkg
1711                    + " id=" + id + " notification=" + notification);
1712        }
1713        if (notification.icon != 0) {
1714            if (!notification.isValid()) {
1715                throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg
1716                        + " id=" + id + " notification=" + notification);
1717            }
1718        }
1719
1720        mHandler.post(new Runnable() {
1721            @Override
1722            public void run() {
1723
1724                synchronized (mNotificationList) {
1725
1726                    // === Scoring ===
1727
1728                    // 0. Sanitize inputs
1729                    notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
1730                            Notification.PRIORITY_MAX);
1731                    // Migrate notification flags to scores
1732                    if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) {
1733                        if (notification.priority < Notification.PRIORITY_MAX) {
1734                            notification.priority = Notification.PRIORITY_MAX;
1735                        }
1736                    } else if (SCORE_ONGOING_HIGHER &&
1737                            0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) {
1738                        if (notification.priority < Notification.PRIORITY_HIGH) {
1739                            notification.priority = Notification.PRIORITY_HIGH;
1740                        }
1741                    }
1742
1743                    // 1. initial score: buckets of 10, around the app [-20..20]
1744                    final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER;
1745
1746                    // 2. extract ranking signals from the notification data
1747                    final StatusBarNotification n = new StatusBarNotification(
1748                            pkg, opPkg, id, tag, callingUid, callingPid, score, notification,
1749                            user);
1750                    NotificationRecord r = new NotificationRecord(n, score);
1751                    NotificationRecord old = mNotificationsByKey.get(n.getKey());
1752                    if (old != null) {
1753                        // Retain ranking information from previous record
1754                        r.copyRankingInformation(old);
1755                    }
1756                    mRankingHelper.extractSignals(r);
1757
1758                    // 3. Apply local rules
1759
1760                    // blocked apps
1761                    if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) {
1762                        if (!isSystemNotification) {
1763                            r.score = JUNK_SCORE;
1764                            Slog.e(TAG, "Suppressing notification from package " + pkg
1765                                    + " by user request.");
1766                        }
1767                    }
1768
1769                    if (r.score < SCORE_DISPLAY_THRESHOLD) {
1770                        // Notification will be blocked because the score is too low.
1771                        return;
1772                    }
1773
1774                    // Clear out group children of the old notification if the update causes the
1775                    // group summary to go away. This happens when the old notification was a
1776                    // summary and the new one isn't, or when the old notification was a summary
1777                    // and its group key changed.
1778                    if (old != null && old.getNotification().isGroupSummary() &&
1779                            (!notification.isGroupSummary() ||
1780                                    !old.getGroupKey().equals(r.getGroupKey()))) {
1781                        cancelGroupChildrenLocked(old, callingUid, callingPid, null);
1782                    }
1783
1784                    int index = indexOfNotificationLocked(n.getKey());
1785                    if (index < 0) {
1786                        mNotificationList.add(r);
1787                        mUsageStats.registerPostedByApp(r);
1788                    } else {
1789                        old = mNotificationList.get(index);
1790                        mNotificationList.set(index, r);
1791                        mUsageStats.registerUpdatedByApp(r, old);
1792                        // Make sure we don't lose the foreground service state.
1793                        notification.flags |=
1794                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
1795                        r.isUpdate = true;
1796                    }
1797
1798                    mNotificationsByKey.put(n.getKey(), r);
1799
1800                    // Ensure if this is a foreground service that the proper additional
1801                    // flags are set.
1802                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
1803                        notification.flags |= Notification.FLAG_ONGOING_EVENT
1804                                | Notification.FLAG_NO_CLEAR;
1805                    }
1806
1807                    applyZenModeLocked(r);
1808                    mRankingHelper.sort(mNotificationList);
1809
1810                    if (notification.icon != 0) {
1811                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
1812                        mListeners.notifyPostedLocked(n, oldSbn);
1813                    } else {
1814                        Slog.e(TAG, "Not posting notification with icon==0: " + notification);
1815                        if (old != null && !old.isCanceled) {
1816                            mListeners.notifyRemovedLocked(n);
1817                        }
1818                        // ATTENTION: in a future release we will bail out here
1819                        // so that we do not play sounds, show lights, etc. for invalid
1820                        // notifications
1821                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "
1822                                + n.getPackageName());
1823                    }
1824
1825                    buzzBeepBlinkLocked(r);
1826                }
1827            }
1828        });
1829
1830        idOut[0] = id;
1831    }
1832
1833    private void buzzBeepBlinkLocked(NotificationRecord record) {
1834        boolean buzzBeepBlinked = false;
1835        final Notification notification = record.sbn.getNotification();
1836
1837        // Should this notification make noise, vibe, or use the LED?
1838        final boolean canInterrupt = (record.score >= SCORE_INTERRUPTION_THRESHOLD) &&
1839                !record.isIntercepted();
1840        if (DBG || record.isIntercepted())
1841            Slog.v(TAG,
1842                    "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
1843                            " intercept=" + record.isIntercepted()
1844            );
1845
1846        final int currentUser;
1847        final long token = Binder.clearCallingIdentity();
1848        try {
1849            currentUser = ActivityManager.getCurrentUser();
1850        } finally {
1851            Binder.restoreCallingIdentity(token);
1852        }
1853
1854        // If we're not supposed to beep, vibrate, etc. then don't.
1855        final String disableEffects = disableNotificationEffects(record);
1856        if (disableEffects != null) {
1857            ZenLog.traceDisableEffects(record, disableEffects);
1858        }
1859        if (disableEffects == null
1860                && (!(record.isUpdate
1861                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
1862                && (record.getUserId() == UserHandle.USER_ALL ||
1863                    record.getUserId() == currentUser ||
1864                    mUserProfiles.isCurrentProfile(record.getUserId()))
1865                && canInterrupt
1866                && mSystemReady
1867                && mAudioManager != null) {
1868            if (DBG) Slog.v(TAG, "Interrupting!");
1869
1870            sendAccessibilityEvent(notification, record.sbn.getPackageName());
1871
1872            // sound
1873
1874            // should we use the default notification sound? (indicated either by
1875            // DEFAULT_SOUND or because notification.sound is pointing at
1876            // Settings.System.NOTIFICATION_SOUND)
1877            final boolean useDefaultSound =
1878                   (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
1879                           Settings.System.DEFAULT_NOTIFICATION_URI
1880                                   .equals(notification.sound);
1881
1882            Uri soundUri = null;
1883            boolean hasValidSound = false;
1884
1885            if (useDefaultSound) {
1886                soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
1887
1888                // check to see if the default notification sound is silent
1889                ContentResolver resolver = getContext().getContentResolver();
1890                hasValidSound = Settings.System.getString(resolver,
1891                       Settings.System.NOTIFICATION_SOUND) != null;
1892            } else if (notification.sound != null) {
1893                soundUri = notification.sound;
1894                hasValidSound = (soundUri != null);
1895            }
1896
1897            if (hasValidSound) {
1898                boolean looping =
1899                        (notification.flags & Notification.FLAG_INSISTENT) != 0;
1900                AudioAttributes audioAttributes;
1901                if (notification.audioAttributes != null) {
1902                    audioAttributes = notification.audioAttributes;
1903                } else {
1904                    audioAttributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
1905                }
1906                mSoundNotification = record;
1907                // do not play notifications if stream volume is 0 (typically because
1908                // ringer mode is silent) or if there is a user of exclusive audio focus
1909                if ((mAudioManager.getStreamVolume(
1910                        AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
1911                            && !mAudioManager.isAudioFocusExclusive()) {
1912                    final long identity = Binder.clearCallingIdentity();
1913                    try {
1914                        final IRingtonePlayer player =
1915                                mAudioManager.getRingtonePlayer();
1916                        if (player != null) {
1917                            if (DBG) Slog.v(TAG, "Playing sound " + soundUri
1918                                    + " with attributes " + audioAttributes);
1919                            player.playAsync(soundUri, record.sbn.getUser(), looping,
1920                                    audioAttributes);
1921                            buzzBeepBlinked = true;
1922                        }
1923                    } catch (RemoteException e) {
1924                    } finally {
1925                        Binder.restoreCallingIdentity(identity);
1926                    }
1927                }
1928            }
1929
1930            // vibrate
1931            // Does the notification want to specify its own vibration?
1932            final boolean hasCustomVibrate = notification.vibrate != null;
1933
1934            // new in 4.2: if there was supposed to be a sound and we're in vibrate
1935            // mode, and no other vibration is specified, we fall back to vibration
1936            final boolean convertSoundToVibration =
1937                       !hasCustomVibrate
1938                    && hasValidSound
1939                    && (mAudioManager.getRingerMode()
1940                               == AudioManager.RINGER_MODE_VIBRATE);
1941
1942            // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
1943            final boolean useDefaultVibrate =
1944                    (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
1945
1946            if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
1947                    && !(mAudioManager.getRingerMode()
1948                            == AudioManager.RINGER_MODE_SILENT)) {
1949                mVibrateNotification = record;
1950
1951                if (useDefaultVibrate || convertSoundToVibration) {
1952                    // Escalate privileges so we can use the vibrator even if the
1953                    // notifying app does not have the VIBRATE permission.
1954                    long identity = Binder.clearCallingIdentity();
1955                    try {
1956                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
1957                            useDefaultVibrate ? mDefaultVibrationPattern
1958                                : mFallbackVibrationPattern,
1959                            ((notification.flags & Notification.FLAG_INSISTENT) != 0)
1960                                ? 0: -1, audioAttributesForNotification(notification));
1961                        buzzBeepBlinked = true;
1962                    } finally {
1963                        Binder.restoreCallingIdentity(identity);
1964                    }
1965                } else if (notification.vibrate.length > 1) {
1966                    // If you want your own vibration pattern, you need the VIBRATE
1967                    // permission
1968                    mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
1969                            notification.vibrate,
1970                        ((notification.flags & Notification.FLAG_INSISTENT) != 0)
1971                                ? 0: -1, audioAttributesForNotification(notification));
1972                    buzzBeepBlinked = true;
1973                }
1974            }
1975        }
1976
1977        // light
1978        // release the light
1979        boolean wasShowLights = mLights.remove(record.getKey());
1980        if (mLedNotification != null && record.getKey().equals(mLedNotification.getKey())) {
1981            mLedNotification = null;
1982        }
1983        if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && canInterrupt) {
1984            mLights.add(record.getKey());
1985            updateLightsLocked();
1986            if (mUseAttentionLight) {
1987                mAttentionLight.pulse();
1988            }
1989            buzzBeepBlinked = true;
1990        } else if (wasShowLights) {
1991            updateLightsLocked();
1992        }
1993        if (buzzBeepBlinked) {
1994            mHandler.post(mBuzzBeepBlinked);
1995        }
1996    }
1997
1998    private static AudioAttributes audioAttributesForNotification(Notification n) {
1999        if (n.audioAttributes != null) {
2000            return n.audioAttributes;
2001        } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2002            // the stream type is valid, use it
2003            return new AudioAttributes.Builder()
2004                    .setInternalLegacyStreamType(n.audioStreamType)
2005                    .build();
2006        } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2007            return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2008        } else {
2009            Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2010            return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2011        }
2012    }
2013
2014    void showNextToastLocked() {
2015        ToastRecord record = mToastQueue.get(0);
2016        while (record != null) {
2017            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2018            try {
2019                record.callback.show();
2020                scheduleTimeoutLocked(record);
2021                return;
2022            } catch (RemoteException e) {
2023                Slog.w(TAG, "Object died trying to show notification " + record.callback
2024                        + " in package " + record.pkg);
2025                // remove it from the list and let the process die
2026                int index = mToastQueue.indexOf(record);
2027                if (index >= 0) {
2028                    mToastQueue.remove(index);
2029                }
2030                keepProcessAliveLocked(record.pid);
2031                if (mToastQueue.size() > 0) {
2032                    record = mToastQueue.get(0);
2033                } else {
2034                    record = null;
2035                }
2036            }
2037        }
2038    }
2039
2040    void cancelToastLocked(int index) {
2041        ToastRecord record = mToastQueue.get(index);
2042        try {
2043            record.callback.hide();
2044        } catch (RemoteException e) {
2045            Slog.w(TAG, "Object died trying to hide notification " + record.callback
2046                    + " in package " + record.pkg);
2047            // don't worry about this, we're about to remove it from
2048            // the list anyway
2049        }
2050        mToastQueue.remove(index);
2051        keepProcessAliveLocked(record.pid);
2052        if (mToastQueue.size() > 0) {
2053            // Show the next one. If the callback fails, this will remove
2054            // it from the list, so don't assume that the list hasn't changed
2055            // after this point.
2056            showNextToastLocked();
2057        }
2058    }
2059
2060    private void scheduleTimeoutLocked(ToastRecord r)
2061    {
2062        mHandler.removeCallbacksAndMessages(r);
2063        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
2064        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
2065        mHandler.sendMessageDelayed(m, delay);
2066    }
2067
2068    private void handleTimeout(ToastRecord record)
2069    {
2070        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
2071        synchronized (mToastQueue) {
2072            int index = indexOfToastLocked(record.pkg, record.callback);
2073            if (index >= 0) {
2074                cancelToastLocked(index);
2075            }
2076        }
2077    }
2078
2079    // lock on mToastQueue
2080    int indexOfToastLocked(String pkg, ITransientNotification callback)
2081    {
2082        IBinder cbak = callback.asBinder();
2083        ArrayList<ToastRecord> list = mToastQueue;
2084        int len = list.size();
2085        for (int i=0; i<len; i++) {
2086            ToastRecord r = list.get(i);
2087            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
2088                return i;
2089            }
2090        }
2091        return -1;
2092    }
2093
2094    // lock on mToastQueue
2095    void keepProcessAliveLocked(int pid)
2096    {
2097        int toastCount = 0; // toasts from this pid
2098        ArrayList<ToastRecord> list = mToastQueue;
2099        int N = list.size();
2100        for (int i=0; i<N; i++) {
2101            ToastRecord r = list.get(i);
2102            if (r.pid == pid) {
2103                toastCount++;
2104            }
2105        }
2106        try {
2107            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
2108        } catch (RemoteException e) {
2109            // Shouldn't happen.
2110        }
2111    }
2112
2113    private void handleRankingReconsideration(Message message) {
2114        if (!(message.obj instanceof RankingReconsideration)) return;
2115        RankingReconsideration recon = (RankingReconsideration) message.obj;
2116        recon.run();
2117        boolean changed;
2118        synchronized (mNotificationList) {
2119            final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
2120            if (record == null) {
2121                return;
2122            }
2123            int indexBefore = findNotificationRecordIndexLocked(record);
2124            boolean interceptBefore = record.isIntercepted();
2125            int visibilityBefore = record.getPackageVisibilityOverride();
2126            recon.applyChangesLocked(record);
2127            applyZenModeLocked(record);
2128            mRankingHelper.sort(mNotificationList);
2129            int indexAfter = findNotificationRecordIndexLocked(record);
2130            boolean interceptAfter = record.isIntercepted();
2131            int visibilityAfter = record.getPackageVisibilityOverride();
2132            changed = indexBefore != indexAfter || interceptBefore != interceptAfter
2133                    || visibilityBefore != visibilityAfter;
2134            if (interceptBefore && !interceptAfter) {
2135                buzzBeepBlinkLocked(record);
2136            }
2137        }
2138        if (changed) {
2139            scheduleSendRankingUpdate();
2140        }
2141    }
2142
2143    private void handleRankingConfigChange() {
2144        synchronized (mNotificationList) {
2145            final int N = mNotificationList.size();
2146            ArrayList<String> orderBefore = new ArrayList<String>(N);
2147            int[] visibilities = new int[N];
2148            for (int i = 0; i < N; i++) {
2149                final NotificationRecord r = mNotificationList.get(i);
2150                orderBefore.add(r.getKey());
2151                visibilities[i] = r.getPackageVisibilityOverride();
2152                mRankingHelper.extractSignals(r);
2153            }
2154            for (int i = 0; i < N; i++) {
2155                mRankingHelper.sort(mNotificationList);
2156                final NotificationRecord r = mNotificationList.get(i);
2157                if (!orderBefore.get(i).equals(r.getKey())
2158                        || visibilities[i] != r.getPackageVisibilityOverride()) {
2159                    scheduleSendRankingUpdate();
2160                    return;
2161                }
2162            }
2163        }
2164    }
2165
2166    // let zen mode evaluate this record
2167    private void applyZenModeLocked(NotificationRecord record) {
2168        record.setIntercepted(mZenModeHelper.shouldIntercept(record));
2169    }
2170
2171    // lock on mNotificationList
2172    private int findNotificationRecordIndexLocked(NotificationRecord target) {
2173        return mRankingHelper.indexOf(mNotificationList, target);
2174    }
2175
2176    private void scheduleSendRankingUpdate() {
2177        mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
2178        Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
2179        mHandler.sendMessage(m);
2180    }
2181
2182    private void handleSendRankingUpdate() {
2183        synchronized (mNotificationList) {
2184            mListeners.notifyRankingUpdateLocked();
2185        }
2186    }
2187
2188    private void scheduleListenerHintsChanged(int state) {
2189        mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
2190        mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
2191    }
2192
2193    private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
2194        mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
2195        mHandler.obtainMessage(
2196                MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
2197                listenerInterruptionFilter,
2198                0).sendToTarget();
2199    }
2200
2201    private void handleListenerHintsChanged(int hints) {
2202        synchronized (mNotificationList) {
2203            mListeners.notifyListenerHintsChangedLocked(hints);
2204        }
2205    }
2206
2207    private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
2208        synchronized (mNotificationList) {
2209            mListeners.notifyInterruptionFilterChanged(interruptionFilter);
2210        }
2211    }
2212
2213    private final class WorkerHandler extends Handler
2214    {
2215        @Override
2216        public void handleMessage(Message msg)
2217        {
2218            switch (msg.what)
2219            {
2220                case MESSAGE_TIMEOUT:
2221                    handleTimeout((ToastRecord)msg.obj);
2222                    break;
2223                case MESSAGE_SAVE_POLICY_FILE:
2224                    handleSavePolicyFile();
2225                    break;
2226                case MESSAGE_SEND_RANKING_UPDATE:
2227                    handleSendRankingUpdate();
2228                    break;
2229                case MESSAGE_LISTENER_HINTS_CHANGED:
2230                    handleListenerHintsChanged(msg.arg1);
2231                    break;
2232                case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
2233                    handleListenerInterruptionFilterChanged(msg.arg1);
2234                    break;
2235            }
2236        }
2237
2238    }
2239
2240    private final class RankingWorkerHandler extends Handler
2241    {
2242        public RankingWorkerHandler(Looper looper) {
2243            super(looper);
2244        }
2245
2246        @Override
2247        public void handleMessage(Message msg) {
2248            switch (msg.what) {
2249                case MESSAGE_RECONSIDER_RANKING:
2250                    handleRankingReconsideration(msg);
2251                    break;
2252                case MESSAGE_RANKING_CONFIG_CHANGE:
2253                    handleRankingConfigChange();
2254                    break;
2255            }
2256        }
2257    }
2258
2259    // Notifications
2260    // ============================================================================
2261    static int clamp(int x, int low, int high) {
2262        return (x < low) ? low : ((x > high) ? high : x);
2263    }
2264
2265    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
2266        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
2267        if (!manager.isEnabled()) {
2268            return;
2269        }
2270
2271        AccessibilityEvent event =
2272            AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
2273        event.setPackageName(packageName);
2274        event.setClassName(Notification.class.getName());
2275        event.setParcelableData(notification);
2276        CharSequence tickerText = notification.tickerText;
2277        if (!TextUtils.isEmpty(tickerText)) {
2278            event.getText().add(tickerText);
2279        }
2280
2281        manager.sendAccessibilityEvent(event);
2282    }
2283
2284    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
2285        // tell the app
2286        if (sendDelete) {
2287            if (r.getNotification().deleteIntent != null) {
2288                try {
2289                    r.getNotification().deleteIntent.send();
2290                } catch (PendingIntent.CanceledException ex) {
2291                    // do nothing - there's no relevant way to recover, and
2292                    //     no reason to let this propagate
2293                    Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
2294                }
2295            }
2296        }
2297
2298        // status bar
2299        if (r.getNotification().icon != 0) {
2300            r.isCanceled = true;
2301            mListeners.notifyRemovedLocked(r.sbn);
2302        }
2303
2304        // sound
2305        if (mSoundNotification == r) {
2306            mSoundNotification = null;
2307            final long identity = Binder.clearCallingIdentity();
2308            try {
2309                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
2310                if (player != null) {
2311                    player.stopAsync();
2312                }
2313            } catch (RemoteException e) {
2314            } finally {
2315                Binder.restoreCallingIdentity(identity);
2316            }
2317        }
2318
2319        // vibrate
2320        if (mVibrateNotification == r) {
2321            mVibrateNotification = null;
2322            long identity = Binder.clearCallingIdentity();
2323            try {
2324                mVibrator.cancel();
2325            }
2326            finally {
2327                Binder.restoreCallingIdentity(identity);
2328            }
2329        }
2330
2331        // light
2332        mLights.remove(r.getKey());
2333        if (mLedNotification == r) {
2334            mLedNotification = null;
2335        }
2336
2337        // Record usage stats
2338        switch (reason) {
2339            case REASON_DELEGATE_CANCEL:
2340            case REASON_DELEGATE_CANCEL_ALL:
2341            case REASON_LISTENER_CANCEL:
2342            case REASON_LISTENER_CANCEL_ALL:
2343                mUsageStats.registerDismissedByUser(r);
2344                break;
2345            case REASON_NOMAN_CANCEL:
2346            case REASON_NOMAN_CANCEL_ALL:
2347                mUsageStats.registerRemovedByApp(r);
2348                break;
2349            case REASON_DELEGATE_CLICK:
2350                mUsageStats.registerCancelDueToClick(r);
2351                break;
2352            default:
2353                mUsageStats.registerCancelUnknown(r);
2354                break;
2355        }
2356
2357        mNotificationsByKey.remove(r.sbn.getKey());
2358
2359        // Save it for users of getHistoricalNotifications()
2360        mArchive.record(r.sbn);
2361    }
2362
2363    /**
2364     * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
2365     * and none of the {@code mustNotHaveFlags}.
2366     */
2367    void cancelNotification(final int callingUid, final int callingPid,
2368            final String pkg, final String tag, final int id,
2369            final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
2370            final int userId, final int reason, final ManagedServiceInfo listener) {
2371        // In enqueueNotificationInternal notifications are added by scheduling the
2372        // work on the worker handler. Hence, we also schedule the cancel on this
2373        // handler to avoid a scenario where an add notification call followed by a
2374        // remove notification call ends up in not removing the notification.
2375        mHandler.post(new Runnable() {
2376            @Override
2377            public void run() {
2378                String listenerName = listener == null ? null : listener.component.toShortString();
2379                EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag, userId,
2380                        mustHaveFlags, mustNotHaveFlags, reason, listenerName);
2381
2382                synchronized (mNotificationList) {
2383                    int index = indexOfNotificationLocked(pkg, tag, id, userId);
2384                    if (index >= 0) {
2385                        NotificationRecord r = mNotificationList.get(index);
2386
2387                        // Ideally we'd do this in the caller of this method. However, that would
2388                        // require the caller to also find the notification.
2389                        if (reason == REASON_DELEGATE_CLICK) {
2390                            mUsageStats.registerClickedByUser(r);
2391                        }
2392
2393                        if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
2394                            return;
2395                        }
2396                        if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
2397                            return;
2398                        }
2399
2400                        mNotificationList.remove(index);
2401
2402                        cancelNotificationLocked(r, sendDelete, reason);
2403                        cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName);
2404                        updateLightsLocked();
2405                    }
2406                }
2407            }
2408        });
2409    }
2410
2411    /**
2412     * Determine whether the userId applies to the notification in question, either because
2413     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
2414     */
2415    private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
2416        return
2417                // looking for USER_ALL notifications? match everything
2418                   userId == UserHandle.USER_ALL
2419                // a notification sent to USER_ALL matches any query
2420                || r.getUserId() == UserHandle.USER_ALL
2421                // an exact user match
2422                || r.getUserId() == userId;
2423    }
2424
2425    /**
2426     * Determine whether the userId applies to the notification in question, either because
2427     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
2428     * because it matches one of the users profiles.
2429     */
2430    private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
2431        return notificationMatchesUserId(r, userId)
2432                || mUserProfiles.isCurrentProfile(r.getUserId());
2433    }
2434
2435    /**
2436     * Cancels all notifications from a given package that have all of the
2437     * {@code mustHaveFlags}.
2438     */
2439    boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
2440            int mustNotHaveFlags, boolean doit, int userId, int reason,
2441            ManagedServiceInfo listener) {
2442        String listenerName = listener == null ? null : listener.component.toShortString();
2443        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
2444                pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
2445                listenerName);
2446
2447        synchronized (mNotificationList) {
2448            final int N = mNotificationList.size();
2449            ArrayList<NotificationRecord> canceledNotifications = null;
2450            for (int i = N-1; i >= 0; --i) {
2451                NotificationRecord r = mNotificationList.get(i);
2452                if (!notificationMatchesUserId(r, userId)) {
2453                    continue;
2454                }
2455                // Don't remove notifications to all, if there's no package name specified
2456                if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
2457                    continue;
2458                }
2459                if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
2460                    continue;
2461                }
2462                if ((r.getFlags() & mustNotHaveFlags) != 0) {
2463                    continue;
2464                }
2465                if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
2466                    continue;
2467                }
2468                if (canceledNotifications == null) {
2469                    canceledNotifications = new ArrayList<>();
2470                }
2471                canceledNotifications.add(r);
2472                if (!doit) {
2473                    return true;
2474                }
2475                mNotificationList.remove(i);
2476                cancelNotificationLocked(r, false, reason);
2477            }
2478            if (doit && canceledNotifications != null) {
2479                final int M = canceledNotifications.size();
2480                for (int i = 0; i < M; i++) {
2481                    cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
2482                            listenerName);
2483                }
2484            }
2485            if (canceledNotifications != null) {
2486                updateLightsLocked();
2487            }
2488            return canceledNotifications != null;
2489        }
2490    }
2491
2492    void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
2493            ManagedServiceInfo listener, boolean includeCurrentProfiles) {
2494        String listenerName = listener == null ? null : listener.component.toShortString();
2495        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
2496                null, userId, 0, 0, reason, listenerName);
2497
2498        ArrayList<NotificationRecord> canceledNotifications = null;
2499        final int N = mNotificationList.size();
2500        for (int i=N-1; i>=0; i--) {
2501            NotificationRecord r = mNotificationList.get(i);
2502            if (includeCurrentProfiles) {
2503                if (!notificationMatchesCurrentProfiles(r, userId)) {
2504                    continue;
2505                }
2506            } else {
2507                if (!notificationMatchesUserId(r, userId)) {
2508                    continue;
2509                }
2510            }
2511
2512            if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
2513                            | Notification.FLAG_NO_CLEAR)) == 0) {
2514                mNotificationList.remove(i);
2515                cancelNotificationLocked(r, true, reason);
2516                // Make a note so we can cancel children later.
2517                if (canceledNotifications == null) {
2518                    canceledNotifications = new ArrayList<>();
2519                }
2520                canceledNotifications.add(r);
2521            }
2522        }
2523        int M = canceledNotifications != null ? canceledNotifications.size() : 0;
2524        for (int i = 0; i < M; i++) {
2525            cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
2526                    listenerName);
2527        }
2528        updateLightsLocked();
2529    }
2530
2531    // Warning: The caller is responsible for invoking updateLightsLocked().
2532    private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
2533            String listenerName) {
2534        Notification n = r.getNotification();
2535        if (!n.isGroupSummary()) {
2536            return;
2537        }
2538
2539        String pkg = r.sbn.getPackageName();
2540        int userId = r.getUserId();
2541
2542        if (pkg == null) {
2543            if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
2544            return;
2545        }
2546
2547        final int N = mNotificationList.size();
2548        for (int i = N - 1; i >= 0; i--) {
2549            NotificationRecord childR = mNotificationList.get(i);
2550            StatusBarNotification childSbn = childR.sbn;
2551            if (childR.getNotification().isGroupChild() &&
2552                    childR.getGroupKey().equals(r.getGroupKey())) {
2553                EventLogTags.writeNotificationCancel(callingUid, callingPid,
2554                        pkg, childSbn.getId(), childSbn.getTag(), userId, 0, 0,
2555                        REASON_GROUP_SUMMARY_CANCELED, listenerName);
2556                mNotificationList.remove(i);
2557                cancelNotificationLocked(childR, false, REASON_GROUP_SUMMARY_CANCELED);
2558            }
2559        }
2560    }
2561
2562    // lock on mNotificationList
2563    void updateLightsLocked()
2564    {
2565        // handle notification lights
2566        if (mLedNotification == null) {
2567            // get next notification, if any
2568            int n = mLights.size();
2569            if (n > 0) {
2570                mLedNotification = mNotificationsByKey.get(mLights.get(n-1));
2571            }
2572        }
2573
2574        // Don't flash while we are in a call or screen is on
2575        if (mLedNotification == null || mInCall || mScreenOn) {
2576            mNotificationLight.turnOff();
2577            mStatusBar.notificationLightOff();
2578        } else {
2579            final Notification ledno = mLedNotification.sbn.getNotification();
2580            int ledARGB = ledno.ledARGB;
2581            int ledOnMS = ledno.ledOnMS;
2582            int ledOffMS = ledno.ledOffMS;
2583            if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
2584                ledARGB = mDefaultNotificationColor;
2585                ledOnMS = mDefaultNotificationLedOn;
2586                ledOffMS = mDefaultNotificationLedOff;
2587            }
2588            if (mNotificationPulseEnabled) {
2589                // pulse repeatedly
2590                mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
2591                        ledOnMS, ledOffMS);
2592            }
2593            // let SystemUI make an independent decision
2594            mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
2595        }
2596    }
2597
2598    // lock on mNotificationList
2599    int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
2600    {
2601        ArrayList<NotificationRecord> list = mNotificationList;
2602        final int len = list.size();
2603        for (int i=0; i<len; i++) {
2604            NotificationRecord r = list.get(i);
2605            if (!notificationMatchesUserId(r, userId) || r.sbn.getId() != id) {
2606                continue;
2607            }
2608            if (tag == null) {
2609                if (r.sbn.getTag() != null) {
2610                    continue;
2611                }
2612            } else {
2613                if (!tag.equals(r.sbn.getTag())) {
2614                    continue;
2615                }
2616            }
2617            if (r.sbn.getPackageName().equals(pkg)) {
2618                return i;
2619            }
2620        }
2621        return -1;
2622    }
2623
2624    // lock on mNotificationList
2625    int indexOfNotificationLocked(String key) {
2626        final int N = mNotificationList.size();
2627        for (int i = 0; i < N; i++) {
2628            if (key.equals(mNotificationList.get(i).getKey())) {
2629                return i;
2630            }
2631        }
2632        return -1;
2633    }
2634
2635    private void updateNotificationPulse() {
2636        synchronized (mNotificationList) {
2637            updateLightsLocked();
2638        }
2639    }
2640
2641    private static boolean isUidSystem(int uid) {
2642        final int appid = UserHandle.getAppId(uid);
2643        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
2644    }
2645
2646    private static boolean isCallerSystem() {
2647        return isUidSystem(Binder.getCallingUid());
2648    }
2649
2650    private static void checkCallerIsSystem() {
2651        if (isCallerSystem()) {
2652            return;
2653        }
2654        throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
2655    }
2656
2657    private static void checkCallerIsSystemOrSameApp(String pkg) {
2658        if (isCallerSystem()) {
2659            return;
2660        }
2661        final int uid = Binder.getCallingUid();
2662        try {
2663            ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
2664                    pkg, 0, UserHandle.getCallingUserId());
2665            if (ai == null) {
2666                throw new SecurityException("Unknown package " + pkg);
2667            }
2668            if (!UserHandle.isSameApp(ai.uid, uid)) {
2669                throw new SecurityException("Calling uid " + uid + " gave package"
2670                        + pkg + " which is owned by uid " + ai.uid);
2671            }
2672        } catch (RemoteException re) {
2673            throw new SecurityException("Unknown package " + pkg + "\n" + re);
2674        }
2675    }
2676
2677    private static String callStateToString(int state) {
2678        switch (state) {
2679            case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
2680            case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
2681            case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
2682            default: return "CALL_STATE_UNKNOWN_" + state;
2683        }
2684    }
2685
2686    private void listenForCallState() {
2687        TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
2688            @Override
2689            public void onCallStateChanged(int state, String incomingNumber) {
2690                if (mCallState == state) return;
2691                if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
2692                mCallState = state;
2693            }
2694        }, PhoneStateListener.LISTEN_CALL_STATE);
2695    }
2696
2697    /**
2698     * Generates a NotificationRankingUpdate from 'sbns', considering only
2699     * notifications visible to the given listener.
2700     *
2701     * <p>Caller must hold a lock on mNotificationList.</p>
2702     */
2703    private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
2704        int speedBumpIndex = -1;
2705        final int N = mNotificationList.size();
2706        ArrayList<String> keys = new ArrayList<String>(N);
2707        ArrayList<String> interceptedKeys = new ArrayList<String>(N);
2708        Bundle visibilityOverrides = new Bundle();
2709        for (int i = 0; i < N; i++) {
2710            NotificationRecord record = mNotificationList.get(i);
2711            if (!isVisibleToListener(record.sbn, info)) {
2712                continue;
2713            }
2714            keys.add(record.sbn.getKey());
2715            if (record.isIntercepted()) {
2716                interceptedKeys.add(record.sbn.getKey());
2717            }
2718            if (record.getPackageVisibilityOverride()
2719                    != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
2720                visibilityOverrides.putInt(record.sbn.getKey(),
2721                        record.getPackageVisibilityOverride());
2722            }
2723            // Find first min-prio notification for speedbump placement.
2724            if (speedBumpIndex == -1 &&
2725                    // Intrusiveness trumps priority, hence ignore intrusives.
2726                    !record.isRecentlyIntrusive() &&
2727                    // Currently, package priority is either PRIORITY_DEFAULT or PRIORITY_MAX, so
2728                    // scanning for PRIORITY_MIN within the package bucket PRIORITY_DEFAULT
2729                    // (or lower as a safeguard) is sufficient to find the speedbump index.
2730                    // We'll have to revisit this when more package priority buckets are introduced.
2731                    record.getPackagePriority() <= Notification.PRIORITY_DEFAULT &&
2732                    record.sbn.getNotification().priority == Notification.PRIORITY_MIN) {
2733                speedBumpIndex = keys.size() - 1;
2734            }
2735        }
2736        String[] keysAr = keys.toArray(new String[keys.size()]);
2737        String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
2738        return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
2739                speedBumpIndex);
2740    }
2741
2742    private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
2743        if (!listener.enabledAndUserMatches(sbn.getUserId())) {
2744            return false;
2745        }
2746        // TODO: remove this for older listeners.
2747        return true;
2748    }
2749
2750    public class NotificationListeners extends ManagedServices {
2751
2752        private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
2753
2754        public NotificationListeners() {
2755            super(getContext(), mHandler, mNotificationList, mUserProfiles);
2756        }
2757
2758        @Override
2759        protected Config getConfig() {
2760            Config c = new Config();
2761            c.caption = "notification listener";
2762            c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
2763            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
2764            c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
2765            c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
2766            c.clientLabel = R.string.notification_listener_binding_label;
2767            return c;
2768        }
2769
2770        @Override
2771        protected IInterface asInterface(IBinder binder) {
2772            return INotificationListener.Stub.asInterface(binder);
2773        }
2774
2775        @Override
2776        public void onServiceAdded(ManagedServiceInfo info) {
2777            final INotificationListener listener = (INotificationListener) info.service;
2778            final NotificationRankingUpdate update;
2779            synchronized (mNotificationList) {
2780                update = makeRankingUpdateLocked(info);
2781            }
2782            try {
2783                listener.onListenerConnected(update);
2784            } catch (RemoteException e) {
2785                // we tried
2786            }
2787        }
2788
2789        @Override
2790        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
2791            if (mListenersDisablingEffects.remove(removed)) {
2792                updateListenerHintsLocked();
2793            }
2794            mLightTrimListeners.remove(removed);
2795        }
2796
2797        public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
2798            if (trim == TRIM_LIGHT) {
2799                mLightTrimListeners.add(info);
2800            } else {
2801                mLightTrimListeners.remove(info);
2802            }
2803        }
2804
2805        public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
2806            return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
2807
2808        }
2809
2810        /**
2811         * asynchronously notify all listeners about a new notification
2812         *
2813         * <p>
2814         * Also takes care of removing a notification that has been visible to a listener before,
2815         * but isn't anymore.
2816         */
2817        public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
2818            // Lazily initialized snapshots of the notification.
2819            StatusBarNotification sbnClone = null;
2820            StatusBarNotification sbnCloneLight = null;
2821
2822            for (final ManagedServiceInfo info : mServices) {
2823                boolean sbnVisible = isVisibleToListener(sbn, info);
2824                boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
2825                // This notification hasn't been and still isn't visible -> ignore.
2826                if (!oldSbnVisible && !sbnVisible) {
2827                    continue;
2828                }
2829                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
2830
2831                // This notification became invisible -> remove the old one.
2832                if (oldSbnVisible && !sbnVisible) {
2833                    final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
2834                    mHandler.post(new Runnable() {
2835                        @Override
2836                        public void run() {
2837                            notifyRemoved(info, oldSbnLightClone, update);
2838                        }
2839                    });
2840                    continue;
2841                }
2842
2843                final int trim = mListeners.getOnNotificationPostedTrim(info);
2844
2845                if (trim == TRIM_LIGHT && sbnCloneLight == null) {
2846                    sbnCloneLight = sbn.cloneLight();
2847                } else if (trim == TRIM_FULL && sbnClone == null) {
2848                    sbnClone = sbn.clone();
2849                }
2850                final StatusBarNotification sbnToPost =
2851                        (trim == TRIM_FULL) ? sbnClone : sbnCloneLight;
2852
2853                mHandler.post(new Runnable() {
2854                    @Override
2855                    public void run() {
2856                        notifyPosted(info, sbnToPost, update);
2857                    }
2858                });
2859            }
2860        }
2861
2862        /**
2863         * asynchronously notify all listeners about a removed notification
2864         */
2865        public void notifyRemovedLocked(StatusBarNotification sbn) {
2866            // make a copy in case changes are made to the underlying Notification object
2867            // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
2868            // notification
2869            final StatusBarNotification sbnLight = sbn.cloneLight();
2870            for (final ManagedServiceInfo info : mServices) {
2871                if (!isVisibleToListener(sbn, info)) {
2872                    continue;
2873                }
2874                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
2875                mHandler.post(new Runnable() {
2876                    @Override
2877                    public void run() {
2878                        notifyRemoved(info, sbnLight, update);
2879                    }
2880                });
2881            }
2882        }
2883
2884        /**
2885         * asynchronously notify all listeners about a reordering of notifications
2886         */
2887        public void notifyRankingUpdateLocked() {
2888            for (final ManagedServiceInfo serviceInfo : mServices) {
2889                if (!serviceInfo.isEnabledForCurrentProfiles()) {
2890                    continue;
2891                }
2892                final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
2893                mHandler.post(new Runnable() {
2894                    @Override
2895                    public void run() {
2896                        notifyRankingUpdate(serviceInfo, update);
2897                    }
2898                });
2899            }
2900        }
2901
2902        public void notifyListenerHintsChangedLocked(final int hints) {
2903            for (final ManagedServiceInfo serviceInfo : mServices) {
2904                if (!serviceInfo.isEnabledForCurrentProfiles()) {
2905                    continue;
2906                }
2907                mHandler.post(new Runnable() {
2908                    @Override
2909                    public void run() {
2910                        notifyListenerHintsChanged(serviceInfo, hints);
2911                    }
2912                });
2913            }
2914        }
2915
2916        public void notifyInterruptionFilterChanged(final int interruptionFilter) {
2917            for (final ManagedServiceInfo serviceInfo : mServices) {
2918                if (!serviceInfo.isEnabledForCurrentProfiles()) {
2919                    continue;
2920                }
2921                mHandler.post(new Runnable() {
2922                    @Override
2923                    public void run() {
2924                        notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
2925                    }
2926                });
2927            }
2928        }
2929
2930        private void notifyPosted(final ManagedServiceInfo info,
2931                final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
2932            final INotificationListener listener = (INotificationListener)info.service;
2933            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
2934            try {
2935                listener.onNotificationPosted(sbnHolder, rankingUpdate);
2936            } catch (RemoteException ex) {
2937                Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
2938            }
2939        }
2940
2941        private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
2942                NotificationRankingUpdate rankingUpdate) {
2943            if (!info.enabledAndUserMatches(sbn.getUserId())) {
2944                return;
2945            }
2946            final INotificationListener listener = (INotificationListener) info.service;
2947            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
2948            try {
2949                listener.onNotificationRemoved(sbnHolder, rankingUpdate);
2950            } catch (RemoteException ex) {
2951                Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
2952            }
2953        }
2954
2955        private void notifyRankingUpdate(ManagedServiceInfo info,
2956                                         NotificationRankingUpdate rankingUpdate) {
2957            final INotificationListener listener = (INotificationListener) info.service;
2958            try {
2959                listener.onNotificationRankingUpdate(rankingUpdate);
2960            } catch (RemoteException ex) {
2961                Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
2962            }
2963        }
2964
2965        private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
2966            final INotificationListener listener = (INotificationListener) info.service;
2967            try {
2968                listener.onListenerHintsChanged(hints);
2969            } catch (RemoteException ex) {
2970                Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
2971            }
2972        }
2973
2974        private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
2975                int interruptionFilter) {
2976            final INotificationListener listener = (INotificationListener) info.service;
2977            try {
2978                listener.onInterruptionFilterChanged(interruptionFilter);
2979            } catch (RemoteException ex) {
2980                Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
2981            }
2982        }
2983
2984        private boolean isListenerPackage(String packageName) {
2985            if (packageName == null) {
2986                return false;
2987            }
2988            // TODO: clean up locking object later
2989            synchronized (mNotificationList) {
2990                for (final ManagedServiceInfo serviceInfo : mServices) {
2991                    if (packageName.equals(serviceInfo.component.getPackageName())) {
2992                        return true;
2993                    }
2994                }
2995            }
2996            return false;
2997        }
2998    }
2999
3000    public static final class DumpFilter {
3001        public String pkgFilter;
3002        public boolean zen;
3003
3004        public static DumpFilter parseFromArguments(String[] args) {
3005            if (args != null && args.length == 2 && "p".equals(args[0])
3006                    && args[1] != null && !args[1].trim().isEmpty()) {
3007                final DumpFilter filter = new DumpFilter();
3008                filter.pkgFilter = args[1].trim().toLowerCase();
3009                return filter;
3010            }
3011            if (args != null && args.length == 1 && "zen".equals(args[0])) {
3012                final DumpFilter filter = new DumpFilter();
3013                filter.zen = true;
3014                return filter;
3015            }
3016            return null;
3017        }
3018
3019        public boolean matches(StatusBarNotification sbn) {
3020            return zen ? true : sbn != null
3021                    && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
3022        }
3023
3024        public boolean matches(ComponentName component) {
3025            return zen ? true : component != null && matches(component.getPackageName());
3026        }
3027
3028        public boolean matches(String pkg) {
3029            return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
3030        }
3031
3032        @Override
3033        public String toString() {
3034            return zen ? "zen" : ('\'' + pkgFilter + '\'');
3035        }
3036    }
3037
3038    /**
3039     * Wrapper for a StatusBarNotification object that allows transfer across a oneway
3040     * binder without sending large amounts of data over a oneway transaction.
3041     */
3042    private static final class StatusBarNotificationHolder
3043            extends IStatusBarNotificationHolder.Stub {
3044        private StatusBarNotification mValue;
3045
3046        public StatusBarNotificationHolder(StatusBarNotification value) {
3047            mValue = value;
3048        }
3049
3050        /** Get the held value and clear it. This function should only be called once per holder */
3051        @Override
3052        public StatusBarNotification get() {
3053            StatusBarNotification value = mValue;
3054            mValue = null;
3055            return value;
3056        }
3057    }
3058}
3059