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