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