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