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