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