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