NotificationManagerService.java revision eae43fbd1712a009c4a59760bf9588b3092e1e37
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<Integer, 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            final String autoGroupKey = adjustment.getSignals().getString(
2183                    Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2184            if (autoGroupKey == null) {
2185                EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2186            } else {
2187                EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2188            }
2189            n.sbn.setOverrideGroupKey(autoGroupKey);
2190        }
2191    }
2192
2193    // Clears the 'fake' auto-bunding summary.
2194    private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
2195        if (adjustment.getSignals() != null) {
2196            Bundle.setDefusable(adjustment.getSignals(), true);
2197            if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
2198                && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2199                ArrayMap<String, String> summaries =
2200                        mAutobundledSummaries.get(adjustment.getUser());
2201                if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
2202                    // Clear summary.
2203                    final NotificationRecord removed = mNotificationsByKey.get(
2204                            summaries.remove(adjustment.getPackage()));
2205                    if (removed != null) {
2206                        mNotificationList.remove(removed);
2207                        cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2208                    }
2209                }
2210            }
2211        }
2212    }
2213
2214    // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2215    private void maybeAddAutobundleSummary(Adjustment adjustment) {
2216        if (adjustment.getSignals() != null) {
2217            Bundle.setDefusable(adjustment.getSignals(), true);
2218            if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2219                final String newAutoBundleKey =
2220                        adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2221                int userId = -1;
2222                NotificationRecord summaryRecord = null;
2223                synchronized (mNotificationList) {
2224                    final StatusBarNotification adjustedSbn
2225                            = mNotificationsByKey.get(adjustment.getKey()).sbn;
2226                    userId = adjustedSbn.getUser().getIdentifier();
2227                    ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2228                    if (summaries == null) {
2229                        summaries = new ArrayMap<>();
2230                    }
2231                    mAutobundledSummaries.put(userId, summaries);
2232                    if (!summaries.containsKey(adjustment.getPackage())
2233                            && newAutoBundleKey != null) {
2234                        // Add summary
2235                        final ApplicationInfo appInfo =
2236                                adjustedSbn.getNotification().extras.getParcelable(
2237                                        Notification.EXTRA_BUILDER_APPLICATION_INFO);
2238                        final Bundle extras = new Bundle();
2239                        extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2240                        final Notification summaryNotification =
2241                                new Notification.Builder(getContext()).setSmallIcon(
2242                                        adjustedSbn.getNotification().getSmallIcon())
2243                                        .setGroupSummary(true)
2244                                        .setGroup(newAutoBundleKey)
2245                                        .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2246                                        .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2247                                        .build();
2248                        summaryNotification.extras.putAll(extras);
2249                        Intent appIntent = getContext().getPackageManager()
2250                                .getLaunchIntentForPackage(adjustment.getPackage());
2251                        if (appIntent != null) {
2252                            summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2253                                    getContext(), 0, appIntent, 0, null,
2254                                    UserHandle.of(userId));
2255                        }
2256                        final StatusBarNotification summarySbn =
2257                                new StatusBarNotification(adjustedSbn.getPackageName(),
2258                                        adjustedSbn.getOpPkg(),
2259                                        Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2260                                        adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2261                                        summaryNotification, adjustedSbn.getUser(),
2262                                        newAutoBundleKey,
2263                                        System.currentTimeMillis());
2264                        summaryRecord = new NotificationRecord(getContext(), summarySbn);
2265                        summaries.put(adjustment.getPackage(), summarySbn.getKey());
2266                    }
2267                }
2268                if (summaryRecord != null) {
2269                    mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2270                }
2271            }
2272        }
2273    }
2274
2275    private String disableNotificationEffects(NotificationRecord record) {
2276        if (mDisableNotificationEffects) {
2277            return "booleanState";
2278        }
2279        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2280            return "listenerHints";
2281        }
2282        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2283            return "callState";
2284        }
2285        return null;
2286    };
2287
2288    private void dumpJson(PrintWriter pw, DumpFilter filter) {
2289        JSONObject dump = new JSONObject();
2290        try {
2291            dump.put("service", "Notification Manager");
2292            dump.put("bans", mRankingHelper.dumpBansJson(filter));
2293            dump.put("ranking", mRankingHelper.dumpJson(filter));
2294            dump.put("stats", mUsageStats.dumpJson(filter));
2295        } catch (JSONException e) {
2296            e.printStackTrace();
2297        }
2298        pw.println(dump);
2299    }
2300
2301    void dumpImpl(PrintWriter pw, DumpFilter filter) {
2302        pw.print("Current Notification Manager state");
2303        if (filter.filtered) {
2304            pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2305        }
2306        pw.println(':');
2307        int N;
2308        final boolean zenOnly = filter.filtered && filter.zen;
2309
2310        if (!zenOnly) {
2311            synchronized (mToastQueue) {
2312                N = mToastQueue.size();
2313                if (N > 0) {
2314                    pw.println("  Toast Queue:");
2315                    for (int i=0; i<N; i++) {
2316                        mToastQueue.get(i).dump(pw, "    ", filter);
2317                    }
2318                    pw.println("  ");
2319                }
2320            }
2321        }
2322
2323        synchronized (mNotificationList) {
2324            if (!zenOnly) {
2325                N = mNotificationList.size();
2326                if (N > 0) {
2327                    pw.println("  Notification List:");
2328                    for (int i=0; i<N; i++) {
2329                        final NotificationRecord nr = mNotificationList.get(i);
2330                        if (filter.filtered && !filter.matches(nr.sbn)) continue;
2331                        nr.dump(pw, "    ", getContext(), filter.redact);
2332                    }
2333                    pw.println("  ");
2334                }
2335
2336                if (!filter.filtered) {
2337                    N = mLights.size();
2338                    if (N > 0) {
2339                        pw.println("  Lights List:");
2340                        for (int i=0; i<N; i++) {
2341                            if (i == N - 1) {
2342                                pw.print("  > ");
2343                            } else {
2344                                pw.print("    ");
2345                            }
2346                            pw.println(mLights.get(i));
2347                        }
2348                        pw.println("  ");
2349                    }
2350                    pw.println("  mUseAttentionLight=" + mUseAttentionLight);
2351                    pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2352                    pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
2353                    pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
2354                    pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
2355                    pw.println("  mCallState=" + callStateToString(mCallState));
2356                    pw.println("  mSystemReady=" + mSystemReady);
2357                }
2358                pw.println("  mArchive=" + mArchive.toString());
2359                Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2360                int i=0;
2361                while (iter.hasNext()) {
2362                    final StatusBarNotification sbn = iter.next();
2363                    if (filter != null && !filter.matches(sbn)) continue;
2364                    pw.println("    " + sbn);
2365                    if (++i >= 5) {
2366                        if (iter.hasNext()) pw.println("    ...");
2367                        break;
2368                    }
2369                }
2370            }
2371
2372            if (!zenOnly) {
2373                pw.println("\n  Usage Stats:");
2374                mUsageStats.dump(pw, "    ", filter);
2375            }
2376
2377            if (!filter.filtered || zenOnly) {
2378                pw.println("\n  Zen Mode:");
2379                pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
2380                mZenModeHelper.dump(pw, "    ");
2381
2382                pw.println("\n  Zen Log:");
2383                ZenLog.dump(pw, "    ");
2384            }
2385
2386            if (!zenOnly) {
2387                pw.println("\n  Ranking Config:");
2388                mRankingHelper.dump(pw, "    ", filter);
2389
2390                pw.println("\n  Notification listeners:");
2391                mListeners.dump(pw, filter);
2392                pw.print("    mListenerHints: "); pw.println(mListenerHints);
2393                pw.print("    mListenersDisablingEffects: (");
2394                N = mListenersDisablingEffects.size();
2395                for (int i = 0; i < N; i++) {
2396                    final int hint = mListenersDisablingEffects.keyAt(i);
2397                    if (i > 0) pw.print(';');
2398                    pw.print("hint[" + hint + "]:");
2399
2400                    final ArraySet<ManagedServiceInfo> listeners =
2401                            mListenersDisablingEffects.valueAt(i);
2402                    final int listenerSize = listeners.size();
2403
2404                    for (int j = 0; j < listenerSize; j++) {
2405                        if (i > 0) pw.print(',');
2406                        final ManagedServiceInfo listener = listeners.valueAt(i);
2407                        pw.print(listener.component);
2408                    }
2409                }
2410                pw.println(')');
2411                pw.println("\n  mRankerServicePackageName: " + mRankerServicePackageName);
2412                pw.println("\n  Notification ranker services:");
2413                mRankerServices.dump(pw, filter);
2414            }
2415            pw.println("\n  Policy access:");
2416            pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
2417
2418            pw.println("\n  Condition providers:");
2419            mConditionProviders.dump(pw, filter);
2420
2421            pw.println("\n  Group summaries:");
2422            for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2423                NotificationRecord r = entry.getValue();
2424                pw.println("    " + entry.getKey() + " -> " + r.getKey());
2425                if (mNotificationsByKey.get(r.getKey()) != r) {
2426                    pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
2427                    r.dump(pw, "      ", getContext(), filter.redact);
2428                }
2429            }
2430        }
2431    }
2432
2433    /**
2434     * The private API only accessible to the system process.
2435     */
2436    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2437        @Override
2438        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
2439                String tag, int id, Notification notification, int[] idReceived, int userId) {
2440            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
2441                    idReceived, userId);
2442        }
2443
2444        @Override
2445        public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2446                int userId) {
2447            checkCallerIsSystem();
2448            synchronized (mNotificationList) {
2449                int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2450                if (i < 0) {
2451                    Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2452                            + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2453                    return;
2454                }
2455                NotificationRecord r = mNotificationList.get(i);
2456                StatusBarNotification sbn = r.sbn;
2457                // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2458                // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2459                // we have to revert to the flags we received initially *and* force remove
2460                // FLAG_FOREGROUND_SERVICE.
2461                sbn.getNotification().flags =
2462                        (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2463                mRankingHelper.sort(mNotificationList);
2464                mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2465            }
2466        }
2467    };
2468
2469    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
2470            final int callingPid, final String tag, final int id, final Notification notification,
2471            int[] idOut, int incomingUserId) {
2472        if (DBG) {
2473            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2474                    + " notification=" + notification);
2475        }
2476        checkCallerIsSystemOrSameApp(pkg);
2477        final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
2478        final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
2479
2480        final int userId = ActivityManager.handleIncomingUser(callingPid,
2481                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
2482        final UserHandle user = new UserHandle(userId);
2483
2484        // Fix the notification as best we can.
2485        try {
2486            final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2487                    pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2488                    (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2489            Notification.addFieldsFromContext(ai, userId, notification);
2490        } catch (NameNotFoundException e) {
2491            Slog.e(TAG, "Cannot create a context for sending app", e);
2492            return;
2493        }
2494
2495        // Limit the number of notifications that any given package except the android
2496        // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
2497        if (!isSystemNotification && !isNotificationFromListener) {
2498            synchronized (mNotificationList) {
2499                int count = 0;
2500                final int N = mNotificationList.size();
2501                for (int i=0; i<N; i++) {
2502                    final NotificationRecord r = mNotificationList.get(i);
2503                    if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
2504                        if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2505                            break;  // Allow updating existing notification
2506                        }
2507                        count++;
2508                        if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2509                            Slog.e(TAG, "Package has already posted " + count
2510                                    + " notifications.  Not showing more.  package=" + pkg);
2511                            return;
2512                        }
2513                    }
2514                }
2515            }
2516        }
2517
2518        if (pkg == null || notification == null) {
2519            throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2520                    + " id=" + id + " notification=" + notification);
2521        }
2522
2523        // Sanitize inputs
2524        notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2525                Notification.PRIORITY_MAX);
2526
2527        // setup local book-keeping
2528        final StatusBarNotification n = new StatusBarNotification(
2529                pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2530                user);
2531        final NotificationRecord r = new NotificationRecord(getContext(), n);
2532        mHandler.post(new EnqueueNotificationRunnable(userId, r));
2533
2534        idOut[0] = id;
2535    }
2536
2537    private class EnqueueNotificationRunnable implements Runnable {
2538        private final NotificationRecord r;
2539        private final int userId;
2540
2541        EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2542            this.userId = userId;
2543            this.r = r;
2544        };
2545
2546        @Override
2547        public void run() {
2548
2549            synchronized (mNotificationList) {
2550                final StatusBarNotification n = r.sbn;
2551                if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
2552                NotificationRecord old = mNotificationsByKey.get(n.getKey());
2553                if (old != null) {
2554                    // Retain ranking information from previous record
2555                    r.copyRankingInformation(old);
2556                }
2557
2558                final int callingUid = n.getUid();
2559                final int callingPid = n.getInitialPid();
2560                final Notification notification = n.getNotification();
2561                final String pkg = n.getPackageName();
2562                final int id = n.getId();
2563                final String tag = n.getTag();
2564                final boolean isSystemNotification = isUidSystem(callingUid) ||
2565                        ("android".equals(pkg));
2566
2567                // Handle grouped notifications and bail out early if we
2568                // can to avoid extracting signals.
2569                handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2570
2571                // This conditional is a dirty hack to limit the logging done on
2572                //     behalf of the download manager without affecting other apps.
2573                if (!pkg.equals("com.android.providers.downloads")
2574                        || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2575                    int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2576                    if (old != null) {
2577                        enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2578                    }
2579                    EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2580                            pkg, id, tag, userId, notification.toString(),
2581                            enqueueStatus);
2582                }
2583
2584                mRankingHelper.extractSignals(r);
2585
2586                final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2587
2588                // blocked apps
2589                if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
2590                        || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
2591                    if (!isSystemNotification) {
2592                        if (isPackageSuspended) {
2593                            Slog.e(TAG, "Suppressing notification from package due to package "
2594                                    + "suspended by administrator.");
2595                            mUsageStats.registerSuspendedByAdmin(r);
2596                        } else {
2597                            Slog.e(TAG, "Suppressing notification from package by user request.");
2598                            mUsageStats.registerBlocked(r);
2599                        }
2600                        return;
2601                    }
2602                }
2603
2604                // tell the ranker service about the notification
2605                if (mRankerServices.isEnabled()) {
2606                    mRankerServices.onNotificationEnqueued(r);
2607                    // TODO delay the code below here for 100ms or until there is an answer
2608                }
2609
2610
2611                int index = indexOfNotificationLocked(n.getKey());
2612                if (index < 0) {
2613                    mNotificationList.add(r);
2614                    mUsageStats.registerPostedByApp(r);
2615                } else {
2616                    old = mNotificationList.get(index);
2617                    mNotificationList.set(index, r);
2618                    mUsageStats.registerUpdatedByApp(r, old);
2619                    // Make sure we don't lose the foreground service state.
2620                    notification.flags |=
2621                            old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2622                    r.isUpdate = true;
2623                }
2624
2625                mNotificationsByKey.put(n.getKey(), r);
2626
2627                // Ensure if this is a foreground service that the proper additional
2628                // flags are set.
2629                if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2630                    notification.flags |= Notification.FLAG_ONGOING_EVENT
2631                            | Notification.FLAG_NO_CLEAR;
2632                }
2633
2634                applyZenModeLocked(r);
2635                mRankingHelper.sort(mNotificationList);
2636
2637                if (notification.getSmallIcon() != null) {
2638                    StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2639                    mListeners.notifyPostedLocked(n, oldSbn);
2640                } else {
2641                    Slog.e(TAG, "Not posting notification without small icon: " + notification);
2642                    if (old != null && !old.isCanceled) {
2643                        mListeners.notifyRemovedLocked(n);
2644                    }
2645                    // ATTENTION: in a future release we will bail out here
2646                    // so that we do not play sounds, show lights, etc. for invalid
2647                    // notifications
2648                    Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2649                            + n.getPackageName());
2650                }
2651
2652                buzzBeepBlinkLocked(r);
2653            }
2654        }
2655    }
2656
2657    /**
2658     * Ensures that grouped notification receive their special treatment.
2659     *
2660     * <p>Cancels group children if the new notification causes a group to lose
2661     * its summary.</p>
2662     *
2663     * <p>Updates mSummaryByGroupKey.</p>
2664     */
2665    private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2666            int callingUid, int callingPid) {
2667        StatusBarNotification sbn = r.sbn;
2668        Notification n = sbn.getNotification();
2669        String group = sbn.getGroupKey();
2670        boolean isSummary = n.isGroupSummary();
2671
2672        Notification oldN = old != null ? old.sbn.getNotification() : null;
2673        String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2674        boolean oldIsSummary = old != null && oldN.isGroupSummary();
2675
2676        if (oldIsSummary) {
2677            NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2678            if (removedSummary != old) {
2679                String removedKey =
2680                        removedSummary != null ? removedSummary.getKey() : "<null>";
2681                Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2682                        ", removed=" + removedKey);
2683            }
2684        }
2685        if (isSummary) {
2686            mSummaryByGroupKey.put(group, r);
2687        }
2688
2689        // Clear out group children of the old notification if the update
2690        // causes the group summary to go away. This happens when the old
2691        // notification was a summary and the new one isn't, or when the old
2692        // notification was a summary and its group key changed.
2693        if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2694            cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2695                    REASON_GROUP_SUMMARY_CANCELED);
2696        }
2697    }
2698
2699    @VisibleForTesting
2700    void buzzBeepBlinkLocked(NotificationRecord record) {
2701        boolean buzz = false;
2702        boolean beep = false;
2703        boolean blink = false;
2704
2705        final Notification notification = record.sbn.getNotification();
2706        final String key = record.getKey();
2707
2708        // Should this notification make noise, vibe, or use the LED?
2709        final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
2710        final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
2711        if (DBG || record.isIntercepted())
2712            Slog.v(TAG,
2713                    "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2714                            " intercept=" + record.isIntercepted()
2715            );
2716
2717        final int currentUser;
2718        final long token = Binder.clearCallingIdentity();
2719        try {
2720            currentUser = ActivityManager.getCurrentUser();
2721        } finally {
2722            Binder.restoreCallingIdentity(token);
2723        }
2724
2725        // If we're not supposed to beep, vibrate, etc. then don't.
2726        final String disableEffects = disableNotificationEffects(record);
2727        if (disableEffects != null) {
2728            ZenLog.traceDisableEffects(record, disableEffects);
2729        }
2730
2731        // Remember if this notification already owns the notification channels.
2732        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2733        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2734
2735        // These are set inside the conditional if the notification is allowed to make noise.
2736        boolean hasValidVibrate = false;
2737        boolean hasValidSound = false;
2738        if (disableEffects == null
2739                && (record.getUserId() == UserHandle.USER_ALL ||
2740                    record.getUserId() == currentUser ||
2741                    mUserProfiles.isCurrentProfile(record.getUserId()))
2742                && canInterrupt
2743                && mSystemReady
2744                && mAudioManager != null) {
2745            if (DBG) Slog.v(TAG, "Interrupting!");
2746
2747            // should we use the default notification sound? (indicated either by
2748            // DEFAULT_SOUND or because notification.sound is pointing at
2749            // Settings.System.NOTIFICATION_SOUND)
2750            final boolean useDefaultSound =
2751                   (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2752                           Settings.System.DEFAULT_NOTIFICATION_URI
2753                                   .equals(notification.sound);
2754
2755            Uri soundUri = null;
2756            if (useDefaultSound) {
2757                soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2758
2759                // check to see if the default notification sound is silent
2760                ContentResolver resolver = getContext().getContentResolver();
2761                hasValidSound = Settings.System.getString(resolver,
2762                       Settings.System.NOTIFICATION_SOUND) != null;
2763            } else if (notification.sound != null) {
2764                soundUri = notification.sound;
2765                hasValidSound = (soundUri != null);
2766            }
2767
2768            // Does the notification want to specify its own vibration?
2769            final boolean hasCustomVibrate = notification.vibrate != null;
2770
2771            // new in 4.2: if there was supposed to be a sound and we're in vibrate
2772            // mode, and no other vibration is specified, we fall back to vibration
2773            final boolean convertSoundToVibration =
2774                    !hasCustomVibrate
2775                            && hasValidSound
2776                            && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
2777
2778            // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2779            final boolean useDefaultVibrate =
2780                    (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2781
2782            hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2783                    hasCustomVibrate;
2784
2785            // We can alert, and we're allowed to alert, but if the developer asked us to only do
2786            // it once, and we already have, then don't.
2787            if (!(record.isUpdate
2788                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2789
2790                sendAccessibilityEvent(notification, record.sbn.getPackageName());
2791
2792                if (hasValidSound) {
2793                    boolean looping =
2794                            (notification.flags & Notification.FLAG_INSISTENT) != 0;
2795                    AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2796                    mSoundNotificationKey = key;
2797                    // do not play notifications if stream volume is 0 (typically because
2798                    // ringer mode is silent) or if there is a user of exclusive audio focus
2799                    if ((mAudioManager.getStreamVolume(
2800                            AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2801                            && !mAudioManager.isAudioFocusExclusive()) {
2802                        final long identity = Binder.clearCallingIdentity();
2803                        try {
2804                            final IRingtonePlayer player =
2805                                    mAudioManager.getRingtonePlayer();
2806                            if (player != null) {
2807                                if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2808                                        + " with attributes " + audioAttributes);
2809                                player.playAsync(soundUri, record.sbn.getUser(), looping,
2810                                        audioAttributes);
2811                                beep = true;
2812                            }
2813                        } catch (RemoteException e) {
2814                        } finally {
2815                            Binder.restoreCallingIdentity(identity);
2816                        }
2817                    }
2818                }
2819
2820                if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2821                        == AudioManager.RINGER_MODE_SILENT)) {
2822                    mVibrateNotificationKey = key;
2823
2824                    if (useDefaultVibrate || convertSoundToVibration) {
2825                        // Escalate privileges so we can use the vibrator even if the
2826                        // notifying app does not have the VIBRATE permission.
2827                        long identity = Binder.clearCallingIdentity();
2828                        try {
2829                            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2830                                    useDefaultVibrate ? mDefaultVibrationPattern
2831                                            : mFallbackVibrationPattern,
2832                                    ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2833                                            ? 0: -1, audioAttributesForNotification(notification));
2834                            buzz = true;
2835                        } finally {
2836                            Binder.restoreCallingIdentity(identity);
2837                        }
2838                    } else if (notification.vibrate.length > 1) {
2839                        // If you want your own vibration pattern, you need the VIBRATE
2840                        // permission
2841                        mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2842                                notification.vibrate,
2843                                ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2844                                        ? 0: -1, audioAttributesForNotification(notification));
2845                        buzz = true;
2846                    }
2847                }
2848            }
2849
2850        }
2851        // If a notification is updated to remove the actively playing sound or vibrate,
2852        // cancel that feedback now
2853        if (wasBeep && !hasValidSound) {
2854            clearSoundLocked();
2855        }
2856        if (wasBuzz && !hasValidVibrate) {
2857            clearVibrateLocked();
2858        }
2859
2860        // light
2861        // release the light
2862        boolean wasShowLights = mLights.remove(key);
2863        if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2864                && ((record.getSuppressedVisualEffects()
2865                & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
2866            mLights.add(key);
2867            updateLightsLocked();
2868            if (mUseAttentionLight) {
2869                mAttentionLight.pulse();
2870            }
2871            blink = true;
2872        } else if (wasShowLights) {
2873            updateLightsLocked();
2874        }
2875        if (buzz || beep || blink) {
2876            if (((record.getSuppressedVisualEffects()
2877                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
2878                if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2879            } else {
2880                EventLogTags.writeNotificationAlert(key,
2881                        buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2882                mHandler.post(mBuzzBeepBlinked);
2883            }
2884        }
2885    }
2886
2887    private static AudioAttributes audioAttributesForNotification(Notification n) {
2888        if (n.audioAttributes != null
2889                && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2890            // the audio attributes are set and different from the default, use them
2891            return n.audioAttributes;
2892        } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2893            // the stream type is valid, use it
2894            return new AudioAttributes.Builder()
2895                    .setInternalLegacyStreamType(n.audioStreamType)
2896                    .build();
2897        } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2898            return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2899        } else {
2900            Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2901            return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2902        }
2903    }
2904
2905    void showNextToastLocked() {
2906        ToastRecord record = mToastQueue.get(0);
2907        while (record != null) {
2908            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2909            try {
2910                record.callback.show();
2911                scheduleTimeoutLocked(record);
2912                return;
2913            } catch (RemoteException e) {
2914                Slog.w(TAG, "Object died trying to show notification " + record.callback
2915                        + " in package " + record.pkg);
2916                // remove it from the list and let the process die
2917                int index = mToastQueue.indexOf(record);
2918                if (index >= 0) {
2919                    mToastQueue.remove(index);
2920                }
2921                keepProcessAliveLocked(record.pid);
2922                if (mToastQueue.size() > 0) {
2923                    record = mToastQueue.get(0);
2924                } else {
2925                    record = null;
2926                }
2927            }
2928        }
2929    }
2930
2931    void cancelToastLocked(int index) {
2932        ToastRecord record = mToastQueue.get(index);
2933        try {
2934            record.callback.hide();
2935        } catch (RemoteException e) {
2936            Slog.w(TAG, "Object died trying to hide notification " + record.callback
2937                    + " in package " + record.pkg);
2938            // don't worry about this, we're about to remove it from
2939            // the list anyway
2940        }
2941        mToastQueue.remove(index);
2942        keepProcessAliveLocked(record.pid);
2943        if (mToastQueue.size() > 0) {
2944            // Show the next one. If the callback fails, this will remove
2945            // it from the list, so don't assume that the list hasn't changed
2946            // after this point.
2947            showNextToastLocked();
2948        }
2949    }
2950
2951    private void scheduleTimeoutLocked(ToastRecord r)
2952    {
2953        mHandler.removeCallbacksAndMessages(r);
2954        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
2955        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
2956        mHandler.sendMessageDelayed(m, delay);
2957    }
2958
2959    private void handleTimeout(ToastRecord record)
2960    {
2961        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
2962        synchronized (mToastQueue) {
2963            int index = indexOfToastLocked(record.pkg, record.callback);
2964            if (index >= 0) {
2965                cancelToastLocked(index);
2966            }
2967        }
2968    }
2969
2970    // lock on mToastQueue
2971    int indexOfToastLocked(String pkg, ITransientNotification callback)
2972    {
2973        IBinder cbak = callback.asBinder();
2974        ArrayList<ToastRecord> list = mToastQueue;
2975        int len = list.size();
2976        for (int i=0; i<len; i++) {
2977            ToastRecord r = list.get(i);
2978            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
2979                return i;
2980            }
2981        }
2982        return -1;
2983    }
2984
2985    // lock on mToastQueue
2986    void keepProcessAliveLocked(int pid)
2987    {
2988        int toastCount = 0; // toasts from this pid
2989        ArrayList<ToastRecord> list = mToastQueue;
2990        int N = list.size();
2991        for (int i=0; i<N; i++) {
2992            ToastRecord r = list.get(i);
2993            if (r.pid == pid) {
2994                toastCount++;
2995            }
2996        }
2997        try {
2998            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
2999        } catch (RemoteException e) {
3000            // Shouldn't happen.
3001        }
3002    }
3003
3004    private void handleRankingReconsideration(Message message) {
3005        if (!(message.obj instanceof RankingReconsideration)) return;
3006        RankingReconsideration recon = (RankingReconsideration) message.obj;
3007        recon.run();
3008        boolean changed;
3009        synchronized (mNotificationList) {
3010            final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3011            if (record == null) {
3012                return;
3013            }
3014            int indexBefore = findNotificationRecordIndexLocked(record);
3015            boolean interceptBefore = record.isIntercepted();
3016            int visibilityBefore = record.getPackageVisibilityOverride();
3017            recon.applyChangesLocked(record);
3018            applyZenModeLocked(record);
3019            mRankingHelper.sort(mNotificationList);
3020            int indexAfter = findNotificationRecordIndexLocked(record);
3021            boolean interceptAfter = record.isIntercepted();
3022            int visibilityAfter = record.getPackageVisibilityOverride();
3023            changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3024                    || visibilityBefore != visibilityAfter;
3025            if (interceptBefore && !interceptAfter) {
3026                buzzBeepBlinkLocked(record);
3027            }
3028        }
3029        if (changed) {
3030            scheduleSendRankingUpdate();
3031        }
3032    }
3033
3034    private void handleRankingSort() {
3035        synchronized (mNotificationList) {
3036            final int N = mNotificationList.size();
3037            ArrayList<String> orderBefore = new ArrayList<String>(N);
3038            ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3039            int[] visibilities = new int[N];
3040            int[] importances = new int[N];
3041            for (int i = 0; i < N; i++) {
3042                final NotificationRecord r = mNotificationList.get(i);
3043                orderBefore.add(r.getKey());
3044                groupOverrideBefore.add(r.sbn.getGroupKey());
3045                visibilities[i] = r.getPackageVisibilityOverride();
3046                importances[i] = r.getImportance();
3047                mRankingHelper.extractSignals(r);
3048            }
3049            mRankingHelper.sort(mNotificationList);
3050            for (int i = 0; i < N; i++) {
3051                final NotificationRecord r = mNotificationList.get(i);
3052                if (!orderBefore.get(i).equals(r.getKey())
3053                        || visibilities[i] != r.getPackageVisibilityOverride()
3054                        || importances[i] != r.getImportance()
3055                        || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
3056                    scheduleSendRankingUpdate();
3057                    return;
3058                }
3059            }
3060        }
3061    }
3062
3063    // let zen mode evaluate this record
3064    private void applyZenModeLocked(NotificationRecord record) {
3065        record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3066        if (record.isIntercepted()) {
3067            int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3068                    ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3069                    | (mZenModeHelper.shouldSuppressWhenScreenOn()
3070                    ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3071            record.setSuppressedVisualEffects(suppressed);
3072        }
3073    }
3074
3075    // lock on mNotificationList
3076    private int findNotificationRecordIndexLocked(NotificationRecord target) {
3077        return mRankingHelper.indexOf(mNotificationList, target);
3078    }
3079
3080    private void scheduleSendRankingUpdate() {
3081        if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3082            Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3083            mHandler.sendMessage(m);
3084        }
3085    }
3086
3087    private void handleSendRankingUpdate() {
3088        synchronized (mNotificationList) {
3089            mListeners.notifyRankingUpdateLocked();
3090        }
3091    }
3092
3093    private void scheduleListenerHintsChanged(int state) {
3094        mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3095        mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3096    }
3097
3098    private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3099        mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3100        mHandler.obtainMessage(
3101                MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3102                listenerInterruptionFilter,
3103                0).sendToTarget();
3104    }
3105
3106    private void handleListenerHintsChanged(int hints) {
3107        synchronized (mNotificationList) {
3108            mListeners.notifyListenerHintsChangedLocked(hints);
3109        }
3110    }
3111
3112    private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3113        synchronized (mNotificationList) {
3114            mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3115        }
3116    }
3117
3118    private final class WorkerHandler extends Handler
3119    {
3120        @Override
3121        public void handleMessage(Message msg)
3122        {
3123            switch (msg.what)
3124            {
3125                case MESSAGE_TIMEOUT:
3126                    handleTimeout((ToastRecord)msg.obj);
3127                    break;
3128                case MESSAGE_SAVE_POLICY_FILE:
3129                    handleSavePolicyFile();
3130                    break;
3131                case MESSAGE_SEND_RANKING_UPDATE:
3132                    handleSendRankingUpdate();
3133                    break;
3134                case MESSAGE_LISTENER_HINTS_CHANGED:
3135                    handleListenerHintsChanged(msg.arg1);
3136                    break;
3137                case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3138                    handleListenerInterruptionFilterChanged(msg.arg1);
3139                    break;
3140            }
3141        }
3142
3143    }
3144
3145    private final class RankingHandlerWorker extends Handler implements RankingHandler
3146    {
3147        public RankingHandlerWorker(Looper looper) {
3148            super(looper);
3149        }
3150
3151        @Override
3152        public void handleMessage(Message msg) {
3153            switch (msg.what) {
3154                case MESSAGE_RECONSIDER_RANKING:
3155                    handleRankingReconsideration(msg);
3156                    break;
3157                case MESSAGE_RANKING_SORT:
3158                    handleRankingSort();
3159                    break;
3160            }
3161        }
3162
3163        public void requestSort() {
3164            removeMessages(MESSAGE_RANKING_SORT);
3165            sendEmptyMessage(MESSAGE_RANKING_SORT);
3166        }
3167
3168        public void requestReconsideration(RankingReconsideration recon) {
3169            Message m = Message.obtain(this,
3170                    NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3171            long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3172            sendMessageDelayed(m, delay);
3173        }
3174    }
3175
3176    // Notifications
3177    // ============================================================================
3178    static int clamp(int x, int low, int high) {
3179        return (x < low) ? low : ((x > high) ? high : x);
3180    }
3181
3182    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3183        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
3184        if (!manager.isEnabled()) {
3185            return;
3186        }
3187
3188        AccessibilityEvent event =
3189            AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3190        event.setPackageName(packageName);
3191        event.setClassName(Notification.class.getName());
3192        event.setParcelableData(notification);
3193        CharSequence tickerText = notification.tickerText;
3194        if (!TextUtils.isEmpty(tickerText)) {
3195            event.getText().add(tickerText);
3196        }
3197
3198        manager.sendAccessibilityEvent(event);
3199    }
3200
3201    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
3202        // tell the app
3203        if (sendDelete) {
3204            if (r.getNotification().deleteIntent != null) {
3205                try {
3206                    r.getNotification().deleteIntent.send();
3207                } catch (PendingIntent.CanceledException ex) {
3208                    // do nothing - there's no relevant way to recover, and
3209                    //     no reason to let this propagate
3210                    Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
3211                }
3212            }
3213        }
3214
3215        // status bar
3216        if (r.getNotification().getSmallIcon() != null) {
3217            r.isCanceled = true;
3218            mListeners.notifyRemovedLocked(r.sbn);
3219        }
3220
3221        final String canceledKey = r.getKey();
3222
3223        // sound
3224        if (canceledKey.equals(mSoundNotificationKey)) {
3225            mSoundNotificationKey = null;
3226            final long identity = Binder.clearCallingIdentity();
3227            try {
3228                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3229                if (player != null) {
3230                    player.stopAsync();
3231                }
3232            } catch (RemoteException e) {
3233            } finally {
3234                Binder.restoreCallingIdentity(identity);
3235            }
3236        }
3237
3238        // vibrate
3239        if (canceledKey.equals(mVibrateNotificationKey)) {
3240            mVibrateNotificationKey = null;
3241            long identity = Binder.clearCallingIdentity();
3242            try {
3243                mVibrator.cancel();
3244            }
3245            finally {
3246                Binder.restoreCallingIdentity(identity);
3247            }
3248        }
3249
3250        // light
3251        mLights.remove(canceledKey);
3252
3253        // Record usage stats
3254        // TODO: add unbundling stats?
3255        switch (reason) {
3256            case REASON_DELEGATE_CANCEL:
3257            case REASON_DELEGATE_CANCEL_ALL:
3258            case REASON_LISTENER_CANCEL:
3259            case REASON_LISTENER_CANCEL_ALL:
3260                mUsageStats.registerDismissedByUser(r);
3261                break;
3262            case REASON_APP_CANCEL:
3263            case REASON_APP_CANCEL_ALL:
3264                mUsageStats.registerRemovedByApp(r);
3265                break;
3266        }
3267
3268        mNotificationsByKey.remove(r.sbn.getKey());
3269        String groupKey = r.getGroupKey();
3270        NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3271        if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3272            mSummaryByGroupKey.remove(groupKey);
3273        }
3274        final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3275        if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3276            summaries.remove(r.sbn.getPackageName());
3277        }
3278
3279        // Save it for users of getHistoricalNotifications()
3280        mArchive.record(r.sbn);
3281
3282        final long now = System.currentTimeMillis();
3283        EventLogTags.writeNotificationCanceled(canceledKey, reason,
3284                r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
3285    }
3286
3287    /**
3288     * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
3289     * and none of the {@code mustNotHaveFlags}.
3290     */
3291    void cancelNotification(final int callingUid, final int callingPid,
3292            final String pkg, final String tag, final int id,
3293            final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
3294            final int userId, final int reason, final ManagedServiceInfo listener) {
3295        // In enqueueNotificationInternal notifications are added by scheduling the
3296        // work on the worker handler. Hence, we also schedule the cancel on this
3297        // handler to avoid a scenario where an add notification call followed by a
3298        // remove notification call ends up in not removing the notification.
3299        mHandler.post(new Runnable() {
3300            @Override
3301            public void run() {
3302                String listenerName = listener == null ? null : listener.component.toShortString();
3303                if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3304                        userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
3305
3306                synchronized (mNotificationList) {
3307                    int index = indexOfNotificationLocked(pkg, tag, id, userId);
3308                    if (index >= 0) {
3309                        NotificationRecord r = mNotificationList.get(index);
3310
3311                        // Ideally we'd do this in the caller of this method. However, that would
3312                        // require the caller to also find the notification.
3313                        if (reason == REASON_DELEGATE_CLICK) {
3314                            mUsageStats.registerClickedByUser(r);
3315                        }
3316
3317                        if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3318                            return;
3319                        }
3320                        if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3321                            return;
3322                        }
3323
3324                        mNotificationList.remove(index);
3325
3326                        cancelNotificationLocked(r, sendDelete, reason);
3327                        cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3328                                REASON_GROUP_SUMMARY_CANCELED);
3329                        updateLightsLocked();
3330                    }
3331                }
3332            }
3333        });
3334    }
3335
3336    /**
3337     * Determine whether the userId applies to the notification in question, either because
3338     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3339     */
3340    private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3341        return
3342                // looking for USER_ALL notifications? match everything
3343                   userId == UserHandle.USER_ALL
3344                // a notification sent to USER_ALL matches any query
3345                || r.getUserId() == UserHandle.USER_ALL
3346                // an exact user match
3347                || r.getUserId() == userId;
3348    }
3349
3350    /**
3351     * Determine whether the userId applies to the notification in question, either because
3352     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
3353     * because it matches one of the users profiles.
3354     */
3355    private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
3356        return notificationMatchesUserId(r, userId)
3357                || mUserProfiles.isCurrentProfile(r.getUserId());
3358    }
3359
3360    /**
3361     * Cancels all notifications from a given package that have all of the
3362     * {@code mustHaveFlags}.
3363     */
3364    boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
3365            int mustNotHaveFlags, boolean doit, int userId, int reason,
3366            ManagedServiceInfo listener) {
3367        String listenerName = listener == null ? null : listener.component.toShortString();
3368        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3369                pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
3370                listenerName);
3371
3372        synchronized (mNotificationList) {
3373            final int N = mNotificationList.size();
3374            ArrayList<NotificationRecord> canceledNotifications = null;
3375            for (int i = N-1; i >= 0; --i) {
3376                NotificationRecord r = mNotificationList.get(i);
3377                if (!notificationMatchesUserId(r, userId)) {
3378                    continue;
3379                }
3380                // Don't remove notifications to all, if there's no package name specified
3381                if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
3382                    continue;
3383                }
3384                if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
3385                    continue;
3386                }
3387                if ((r.getFlags() & mustNotHaveFlags) != 0) {
3388                    continue;
3389                }
3390                if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
3391                    continue;
3392                }
3393                if (canceledNotifications == null) {
3394                    canceledNotifications = new ArrayList<>();
3395                }
3396                canceledNotifications.add(r);
3397                if (!doit) {
3398                    return true;
3399                }
3400                mNotificationList.remove(i);
3401                cancelNotificationLocked(r, false, reason);
3402            }
3403            if (doit && canceledNotifications != null) {
3404                final int M = canceledNotifications.size();
3405                for (int i = 0; i < M; i++) {
3406                    cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3407                            listenerName, REASON_GROUP_SUMMARY_CANCELED);
3408                }
3409            }
3410            if (canceledNotifications != null) {
3411                updateLightsLocked();
3412            }
3413            return canceledNotifications != null;
3414        }
3415    }
3416
3417    void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
3418            ManagedServiceInfo listener, boolean includeCurrentProfiles) {
3419        String listenerName = listener == null ? null : listener.component.toShortString();
3420        EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3421                null, userId, 0, 0, reason, listenerName);
3422
3423        ArrayList<NotificationRecord> canceledNotifications = null;
3424        final int N = mNotificationList.size();
3425        for (int i=N-1; i>=0; i--) {
3426            NotificationRecord r = mNotificationList.get(i);
3427            if (includeCurrentProfiles) {
3428                if (!notificationMatchesCurrentProfiles(r, userId)) {
3429                    continue;
3430                }
3431            } else {
3432                if (!notificationMatchesUserId(r, userId)) {
3433                    continue;
3434                }
3435            }
3436
3437            if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3438                            | Notification.FLAG_NO_CLEAR)) == 0) {
3439                mNotificationList.remove(i);
3440                cancelNotificationLocked(r, true, reason);
3441                // Make a note so we can cancel children later.
3442                if (canceledNotifications == null) {
3443                    canceledNotifications = new ArrayList<>();
3444                }
3445                canceledNotifications.add(r);
3446            }
3447        }
3448        int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3449        for (int i = 0; i < M; i++) {
3450            cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
3451                    listenerName, REASON_GROUP_SUMMARY_CANCELED);
3452        }
3453        updateLightsLocked();
3454    }
3455
3456    // Warning: The caller is responsible for invoking updateLightsLocked().
3457    private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
3458            String listenerName, int reason) {
3459        Notification n = r.getNotification();
3460        if (!n.isGroupSummary()) {
3461            return;
3462        }
3463
3464        String pkg = r.sbn.getPackageName();
3465        int userId = r.getUserId();
3466
3467        if (pkg == null) {
3468            if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3469            return;
3470        }
3471
3472        final int N = mNotificationList.size();
3473        for (int i = N - 1; i >= 0; i--) {
3474            NotificationRecord childR = mNotificationList.get(i);
3475            StatusBarNotification childSbn = childR.sbn;
3476            if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
3477                    childR.getGroupKey().equals(r.getGroupKey())) {
3478                EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3479                        childSbn.getTag(), userId, 0, 0, reason, listenerName);
3480                mNotificationList.remove(i);
3481                cancelNotificationLocked(childR, false, reason);
3482            }
3483        }
3484    }
3485
3486    // lock on mNotificationList
3487    void updateLightsLocked()
3488    {
3489        // handle notification lights
3490        NotificationRecord ledNotification = null;
3491        while (ledNotification == null && !mLights.isEmpty()) {
3492            final String owner = mLights.get(mLights.size() - 1);
3493            ledNotification = mNotificationsByKey.get(owner);
3494            if (ledNotification == null) {
3495                Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3496                mLights.remove(owner);
3497            }
3498        }
3499
3500        // Don't flash while we are in a call or screen is on
3501        if (ledNotification == null || mInCall || mScreenOn) {
3502            mNotificationLight.turnOff();
3503            if (mStatusBar != null) {
3504                mStatusBar.notificationLightOff();
3505            }
3506        } else {
3507            final Notification ledno = ledNotification.sbn.getNotification();
3508            int ledARGB = ledno.ledARGB;
3509            int ledOnMS = ledno.ledOnMS;
3510            int ledOffMS = ledno.ledOffMS;
3511            if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
3512                ledARGB = mDefaultNotificationColor;
3513                ledOnMS = mDefaultNotificationLedOn;
3514                ledOffMS = mDefaultNotificationLedOff;
3515            }
3516            if (mNotificationPulseEnabled) {
3517                // pulse repeatedly
3518                mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
3519                        ledOnMS, ledOffMS);
3520            }
3521            if (mStatusBar != null) {
3522                // let SystemUI make an independent decision
3523                mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3524            }
3525        }
3526    }
3527
3528    // lock on mNotificationList
3529    int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
3530    {
3531        ArrayList<NotificationRecord> list = mNotificationList;
3532        final int len = list.size();
3533        for (int i=0; i<len; i++) {
3534            NotificationRecord r = list.get(i);
3535            if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3536                    TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
3537                return i;
3538            }
3539        }
3540        return -1;
3541    }
3542
3543    // lock on mNotificationList
3544    int indexOfNotificationLocked(String key) {
3545        final int N = mNotificationList.size();
3546        for (int i = 0; i < N; i++) {
3547            if (key.equals(mNotificationList.get(i).getKey())) {
3548                return i;
3549            }
3550        }
3551        return -1;
3552    }
3553
3554    private void updateNotificationPulse() {
3555        synchronized (mNotificationList) {
3556            updateLightsLocked();
3557        }
3558    }
3559
3560    private static boolean isUidSystem(int uid) {
3561        final int appid = UserHandle.getAppId(uid);
3562        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3563    }
3564
3565    private static boolean isCallerSystem() {
3566        return isUidSystem(Binder.getCallingUid());
3567    }
3568
3569    private static void checkCallerIsSystem() {
3570        if (isCallerSystem()) {
3571            return;
3572        }
3573        throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3574    }
3575
3576    private static void checkCallerIsSystemOrSameApp(String pkg) {
3577        if (isCallerSystem()) {
3578            return;
3579        }
3580        final int uid = Binder.getCallingUid();
3581        try {
3582            ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3583                    pkg, 0, UserHandle.getCallingUserId());
3584            if (ai == null) {
3585                throw new SecurityException("Unknown package " + pkg);
3586            }
3587            if (!UserHandle.isSameApp(ai.uid, uid)) {
3588                throw new SecurityException("Calling uid " + uid + " gave package"
3589                        + pkg + " which is owned by uid " + ai.uid);
3590            }
3591        } catch (RemoteException re) {
3592            throw new SecurityException("Unknown package " + pkg + "\n" + re);
3593        }
3594    }
3595
3596    private static String callStateToString(int state) {
3597        switch (state) {
3598            case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3599            case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3600            case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3601            default: return "CALL_STATE_UNKNOWN_" + state;
3602        }
3603    }
3604
3605    private void listenForCallState() {
3606        TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3607            @Override
3608            public void onCallStateChanged(int state, String incomingNumber) {
3609                if (mCallState == state) return;
3610                if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3611                mCallState = state;
3612            }
3613        }, PhoneStateListener.LISTEN_CALL_STATE);
3614    }
3615
3616    /**
3617     * Generates a NotificationRankingUpdate from 'sbns', considering only
3618     * notifications visible to the given listener.
3619     *
3620     * <p>Caller must hold a lock on mNotificationList.</p>
3621     */
3622    private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
3623        final int N = mNotificationList.size();
3624        ArrayList<String> keys = new ArrayList<String>(N);
3625        ArrayList<String> interceptedKeys = new ArrayList<String>(N);
3626        ArrayList<Integer> importance = new ArrayList<>(N);
3627        Bundle overrideGroupKeys = new Bundle();
3628        Bundle visibilityOverrides = new Bundle();
3629        Bundle suppressedVisualEffects = new Bundle();
3630        Bundle explanation = new Bundle();
3631        for (int i = 0; i < N; i++) {
3632            NotificationRecord record = mNotificationList.get(i);
3633            if (!isVisibleToListener(record.sbn, info)) {
3634                continue;
3635            }
3636            final String key = record.sbn.getKey();
3637            keys.add(key);
3638            importance.add(record.getImportance());
3639            if (record.getImportanceExplanation() != null) {
3640                explanation.putCharSequence(key, record.getImportanceExplanation());
3641            }
3642            if (record.isIntercepted()) {
3643                interceptedKeys.add(key);
3644
3645            }
3646            suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
3647            if (record.getPackageVisibilityOverride()
3648                    != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
3649                visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
3650            }
3651            overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
3652        }
3653        final int M = keys.size();
3654        String[] keysAr = keys.toArray(new String[M]);
3655        String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
3656        int[] importanceAr = new int[M];
3657        for (int i = 0; i < M; i++) {
3658            importanceAr[i] = importance.get(i);
3659        }
3660        return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
3661                suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
3662    }
3663
3664    private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3665        if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3666            return false;
3667        }
3668        // TODO: remove this for older listeners.
3669        return true;
3670    }
3671
3672    private boolean isPackageSuspendedForUser(String pkg, int uid) {
3673        int userId = UserHandle.getUserId(uid);
3674        try {
3675            return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
3676        } catch (RemoteException re) {
3677            throw new SecurityException("Could not talk to package manager service");
3678        } catch (IllegalArgumentException ex) {
3679            // Package not found.
3680            return false;
3681        }
3682    }
3683
3684    private class TrimCache {
3685        StatusBarNotification heavy;
3686        StatusBarNotification sbnClone;
3687        StatusBarNotification sbnCloneLight;
3688
3689        TrimCache(StatusBarNotification sbn) {
3690            heavy = sbn;
3691        }
3692
3693        StatusBarNotification ForListener(ManagedServiceInfo info) {
3694            if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3695                if (sbnCloneLight == null) {
3696                    sbnCloneLight = heavy.cloneLight();
3697                }
3698                return sbnCloneLight;
3699            } else {
3700                if (sbnClone == null) {
3701                    sbnClone = heavy.clone();
3702                }
3703                return sbnClone;
3704            }
3705        }
3706    }
3707
3708    public class NotificationRankers extends ManagedServices {
3709
3710        public NotificationRankers() {
3711            super(getContext(), mHandler, mNotificationList, mUserProfiles);
3712        }
3713
3714        @Override
3715        protected Config getConfig() {
3716            Config c = new Config();
3717            c.caption = "notification ranker service";
3718            c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3719            c.secureSettingName = null;
3720            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
3721            c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3722            c.clientLabel = R.string.notification_ranker_binding_label;
3723            return c;
3724        }
3725
3726        @Override
3727        protected IInterface asInterface(IBinder binder) {
3728            return INotificationListener.Stub.asInterface(binder);
3729        }
3730
3731        @Override
3732        protected boolean checkType(IInterface service) {
3733            return service instanceof INotificationListener;
3734        }
3735
3736        @Override
3737        protected void onServiceAdded(ManagedServiceInfo info) {
3738            mListeners.registerGuestService(info);
3739        }
3740
3741        @Override
3742        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3743            mListeners.unregisterService(removed.service, removed.userid);
3744        }
3745
3746        public void onNotificationEnqueued(final NotificationRecord r) {
3747            final StatusBarNotification sbn = r.sbn;
3748            TrimCache trimCache = new TrimCache(sbn);
3749
3750            // mServices is the list inside ManagedServices of all the rankers,
3751            // There should be only one, but it's a list, so while we enforce
3752            // singularity elsewhere, we keep it general here, to avoid surprises.
3753            for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
3754                boolean sbnVisible = isVisibleToListener(sbn, info);
3755                if (!sbnVisible) {
3756                    continue;
3757                }
3758
3759                final int importance = r.getImportance();
3760                final boolean fromUser = r.isImportanceFromUser();
3761                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
3762                mHandler.post(new Runnable() {
3763                    @Override
3764                    public void run() {
3765                        notifyEnqueued(info, sbnToPost, importance, fromUser);
3766                    }
3767                });
3768            }
3769        }
3770
3771        private void notifyEnqueued(final ManagedServiceInfo info,
3772                final StatusBarNotification sbn, int importance, boolean fromUser) {
3773            final INotificationListener ranker = (INotificationListener) info.service;
3774            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3775            try {
3776                ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
3777            } catch (RemoteException ex) {
3778                Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
3779            }
3780        }
3781
3782        public boolean isEnabled() {
3783            return !mServices.isEmpty();
3784        }
3785
3786        @Override
3787        public void onUserSwitched(int user) {
3788            for (ManagedServiceInfo info : mServices) {
3789                unregisterService(info.service, info.userid);
3790            }
3791            registerRanker();
3792        }
3793
3794        @Override
3795        public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
3796            if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
3797                    + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
3798            if (mRankerServicePackageName == null) {
3799                return;
3800            }
3801
3802            if (pkgList != null && (pkgList.length > 0)) {
3803                for (String pkgName : pkgList) {
3804                    if (mRankerServicePackageName.equals(pkgName)) {
3805                        registerRanker();
3806                    }
3807                }
3808            }
3809        }
3810
3811        protected void registerRanker() {
3812            // Find the updatable ranker and register it.
3813            if (mRankerServicePackageName == null) {
3814                Slog.w(TAG, "could not start ranker service: no package specified!");
3815                return;
3816            }
3817            Set<ComponentName> rankerComponents = queryPackageForServices(
3818                    mRankerServicePackageName, UserHandle.USER_SYSTEM);
3819            Iterator<ComponentName> iterator = rankerComponents.iterator();
3820            if (iterator.hasNext()) {
3821                ComponentName rankerComponent = iterator.next();
3822                if (iterator.hasNext()) {
3823                    Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3824                } else {
3825                    registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3826                }
3827            } else {
3828                Slog.w(TAG, "could not start ranker service: none found");
3829            }
3830        }
3831    }
3832
3833    public class NotificationListeners extends ManagedServices {
3834
3835        private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3836
3837        public NotificationListeners() {
3838            super(getContext(), mHandler, mNotificationList, mUserProfiles);
3839        }
3840
3841        @Override
3842        protected Config getConfig() {
3843            Config c = new Config();
3844            c.caption = "notification listener";
3845            c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3846            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3847            c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3848            c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3849            c.clientLabel = R.string.notification_listener_binding_label;
3850            return c;
3851        }
3852
3853        @Override
3854        protected IInterface asInterface(IBinder binder) {
3855            return INotificationListener.Stub.asInterface(binder);
3856        }
3857
3858        @Override
3859        protected boolean checkType(IInterface service) {
3860            return service instanceof INotificationListener;
3861        }
3862
3863        @Override
3864        public void onServiceAdded(ManagedServiceInfo info) {
3865            final INotificationListener listener = (INotificationListener) info.service;
3866            final NotificationRankingUpdate update;
3867            synchronized (mNotificationList) {
3868                update = makeRankingUpdateLocked(info);
3869            }
3870            try {
3871                listener.onListenerConnected(update);
3872            } catch (RemoteException e) {
3873                // we tried
3874            }
3875        }
3876
3877        @Override
3878        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3879            if (removeDisabledHints(removed)) {
3880                updateListenerHintsLocked();
3881                updateEffectsSuppressorLocked();
3882            }
3883            mLightTrimListeners.remove(removed);
3884        }
3885
3886        public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3887            if (trim == TRIM_LIGHT) {
3888                mLightTrimListeners.add(info);
3889            } else {
3890                mLightTrimListeners.remove(info);
3891            }
3892        }
3893
3894        public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3895            return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
3896        }
3897
3898        /**
3899         * asynchronously notify all listeners about a new notification
3900         *
3901         * <p>
3902         * Also takes care of removing a notification that has been visible to a listener before,
3903         * but isn't anymore.
3904         */
3905        public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
3906            // Lazily initialized snapshots of the notification.
3907            TrimCache trimCache = new TrimCache(sbn);
3908
3909            for (final ManagedServiceInfo info : mServices) {
3910                boolean sbnVisible = isVisibleToListener(sbn, info);
3911                boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3912                // This notification hasn't been and still isn't visible -> ignore.
3913                if (!oldSbnVisible && !sbnVisible) {
3914                    continue;
3915                }
3916                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3917
3918                // This notification became invisible -> remove the old one.
3919                if (oldSbnVisible && !sbnVisible) {
3920                    final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
3921                    mHandler.post(new Runnable() {
3922                        @Override
3923                        public void run() {
3924                            notifyRemoved(info, oldSbnLightClone, update);
3925                        }
3926                    });
3927                    continue;
3928                }
3929
3930                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
3931                mHandler.post(new Runnable() {
3932                    @Override
3933                    public void run() {
3934                        notifyPosted(info, sbnToPost, update);
3935                    }
3936                });
3937            }
3938        }
3939
3940        /**
3941         * asynchronously notify all listeners about a removed notification
3942         */
3943        public void notifyRemovedLocked(StatusBarNotification sbn) {
3944            // make a copy in case changes are made to the underlying Notification object
3945            // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
3946            // notification
3947            final StatusBarNotification sbnLight = sbn.cloneLight();
3948            for (final ManagedServiceInfo info : mServices) {
3949                if (!isVisibleToListener(sbn, info)) {
3950                    continue;
3951                }
3952                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
3953                mHandler.post(new Runnable() {
3954                    @Override
3955                    public void run() {
3956                        notifyRemoved(info, sbnLight, update);
3957                    }
3958                });
3959            }
3960        }
3961
3962        /**
3963         * asynchronously notify all listeners about a reordering of notifications
3964         */
3965        public void notifyRankingUpdateLocked() {
3966            for (final ManagedServiceInfo serviceInfo : mServices) {
3967                if (!serviceInfo.isEnabledForCurrentProfiles()) {
3968                    continue;
3969                }
3970                final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
3971                mHandler.post(new Runnable() {
3972                    @Override
3973                    public void run() {
3974                        notifyRankingUpdate(serviceInfo, update);
3975                    }
3976                });
3977            }
3978        }
3979
3980        public void notifyListenerHintsChangedLocked(final int hints) {
3981            for (final ManagedServiceInfo serviceInfo : mServices) {
3982                if (!serviceInfo.isEnabledForCurrentProfiles()) {
3983                    continue;
3984                }
3985                mHandler.post(new Runnable() {
3986                    @Override
3987                    public void run() {
3988                        notifyListenerHintsChanged(serviceInfo, hints);
3989                    }
3990                });
3991            }
3992        }
3993
3994        public void notifyInterruptionFilterChanged(final int interruptionFilter) {
3995            for (final ManagedServiceInfo serviceInfo : mServices) {
3996                if (!serviceInfo.isEnabledForCurrentProfiles()) {
3997                    continue;
3998                }
3999                mHandler.post(new Runnable() {
4000                    @Override
4001                    public void run() {
4002                        notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4003                    }
4004                });
4005            }
4006        }
4007
4008        private void notifyPosted(final ManagedServiceInfo info,
4009                final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
4010            final INotificationListener listener = (INotificationListener)info.service;
4011            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4012            try {
4013                listener.onNotificationPosted(sbnHolder, rankingUpdate);
4014            } catch (RemoteException ex) {
4015                Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4016            }
4017        }
4018
4019        private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
4020                NotificationRankingUpdate rankingUpdate) {
4021            if (!info.enabledAndUserMatches(sbn.getUserId())) {
4022                return;
4023            }
4024            final INotificationListener listener = (INotificationListener) info.service;
4025            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4026            try {
4027                listener.onNotificationRemoved(sbnHolder, rankingUpdate);
4028            } catch (RemoteException ex) {
4029                Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
4030            }
4031        }
4032
4033        private void notifyRankingUpdate(ManagedServiceInfo info,
4034                                         NotificationRankingUpdate rankingUpdate) {
4035            final INotificationListener listener = (INotificationListener) info.service;
4036            try {
4037                listener.onNotificationRankingUpdate(rankingUpdate);
4038            } catch (RemoteException ex) {
4039                Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4040            }
4041        }
4042
4043        private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
4044            final INotificationListener listener = (INotificationListener) info.service;
4045            try {
4046                listener.onListenerHintsChanged(hints);
4047            } catch (RemoteException ex) {
4048                Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
4049            }
4050        }
4051
4052        private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4053                int interruptionFilter) {
4054            final INotificationListener listener = (INotificationListener) info.service;
4055            try {
4056                listener.onInterruptionFilterChanged(interruptionFilter);
4057            } catch (RemoteException ex) {
4058                Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4059            }
4060        }
4061
4062        private boolean isListenerPackage(String packageName) {
4063            if (packageName == null) {
4064                return false;
4065            }
4066            // TODO: clean up locking object later
4067            synchronized (mNotificationList) {
4068                for (final ManagedServiceInfo serviceInfo : mServices) {
4069                    if (packageName.equals(serviceInfo.component.getPackageName())) {
4070                        return true;
4071                    }
4072                }
4073            }
4074            return false;
4075        }
4076    }
4077
4078    public static final class DumpFilter {
4079        public boolean filtered = false;
4080        public String pkgFilter;
4081        public boolean zen;
4082        public long since;
4083        public boolean stats;
4084        public boolean redact = true;
4085
4086        public static DumpFilter parseFromArguments(String[] args) {
4087            final DumpFilter filter = new DumpFilter();
4088            for (int ai = 0; ai < args.length; ai++) {
4089                final String a = args[ai];
4090                if ("--noredact".equals(a) || "--reveal".equals(a)) {
4091                    filter.redact = false;
4092                } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4093                    if (ai < args.length-1) {
4094                        ai++;
4095                        filter.pkgFilter = args[ai].trim().toLowerCase();
4096                        if (filter.pkgFilter.isEmpty()) {
4097                            filter.pkgFilter = null;
4098                        } else {
4099                            filter.filtered = true;
4100                        }
4101                    }
4102                } else if ("--zen".equals(a) || "zen".equals(a)) {
4103                    filter.filtered = true;
4104                    filter.zen = true;
4105                } else if ("--stats".equals(a)) {
4106                    filter.stats = true;
4107                    if (ai < args.length-1) {
4108                        ai++;
4109                        filter.since = Long.valueOf(args[ai]);
4110                    } else {
4111                        filter.since = 0;
4112                    }
4113                }
4114            }
4115            return filter;
4116        }
4117
4118        public boolean matches(StatusBarNotification sbn) {
4119            if (!filtered) return true;
4120            return zen ? true : sbn != null
4121                    && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
4122        }
4123
4124        public boolean matches(ComponentName component) {
4125            if (!filtered) return true;
4126            return zen ? true : component != null && matches(component.getPackageName());
4127        }
4128
4129        public boolean matches(String pkg) {
4130            if (!filtered) return true;
4131            return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
4132        }
4133
4134        @Override
4135        public String toString() {
4136            return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
4137        }
4138    }
4139
4140    /**
4141     * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4142     * binder without sending large amounts of data over a oneway transaction.
4143     */
4144    private static final class StatusBarNotificationHolder
4145            extends IStatusBarNotificationHolder.Stub {
4146        private StatusBarNotification mValue;
4147
4148        public StatusBarNotificationHolder(StatusBarNotification value) {
4149            mValue = value;
4150        }
4151
4152        /** Get the held value and clear it. This function should only be called once per holder */
4153        @Override
4154        public StatusBarNotification get() {
4155            StatusBarNotification value = mValue;
4156            mValue = null;
4157            return value;
4158        }
4159    }
4160
4161    private final class PolicyAccess {
4162        private static final String SEPARATOR = ":";
4163        private final String[] PERM = {
4164            android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4165        };
4166
4167        public boolean isPackageGranted(String pkg) {
4168            return pkg != null && getGrantedPackages().contains(pkg);
4169        }
4170
4171        public void put(String pkg, boolean granted) {
4172            if (pkg == null) return;
4173            final ArraySet<String> pkgs = getGrantedPackages();
4174            boolean changed;
4175            if (granted) {
4176                changed = pkgs.add(pkg);
4177            } else {
4178                changed = pkgs.remove(pkg);
4179            }
4180            if (!changed) return;
4181            final String setting = TextUtils.join(SEPARATOR, pkgs);
4182            final int currentUser = ActivityManager.getCurrentUser();
4183            Settings.Secure.putStringForUser(getContext().getContentResolver(),
4184                    Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4185                    setting,
4186                    currentUser);
4187            getContext().sendBroadcastAsUser(new Intent(NotificationManager
4188                    .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4189                .setPackage(pkg)
4190                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4191        }
4192
4193        public ArraySet<String> getGrantedPackages() {
4194            final ArraySet<String> pkgs = new ArraySet<>();
4195
4196            long identity = Binder.clearCallingIdentity();
4197            try {
4198                final String setting = Settings.Secure.getStringForUser(
4199                        getContext().getContentResolver(),
4200                        Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4201                        ActivityManager.getCurrentUser());
4202                if (setting != null) {
4203                    final String[] tokens = setting.split(SEPARATOR);
4204                    for (int i = 0; i < tokens.length; i++) {
4205                        String token = tokens[i];
4206                        if (token != null) {
4207                            token = token.trim();
4208                        }
4209                        if (TextUtils.isEmpty(token)) {
4210                            continue;
4211                        }
4212                        pkgs.add(token);
4213                    }
4214                }
4215            } finally {
4216                Binder.restoreCallingIdentity(identity);
4217            }
4218            return pkgs;
4219        }
4220
4221        public String[] getRequestingPackages() throws RemoteException {
4222            final ParceledListSlice list = AppGlobals.getPackageManager()
4223                    .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4224                            ActivityManager.getCurrentUser());
4225            final List<PackageInfo> pkgs = list.getList();
4226            if (pkgs == null || pkgs.isEmpty()) return new String[0];
4227            final int N = pkgs.size();
4228            final String[] rt = new String[N];
4229            for (int i = 0; i < N; i++) {
4230                rt[i] = pkgs.get(i).packageName;
4231            }
4232            return rt;
4233        }
4234    }
4235}
4236