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