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