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