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