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