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