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