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