NotificationManagerService.java revision 018aa621aaaafd6adb810b2102eb3e503a14f708
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.app.NotificationManager.IMPORTANCE_NONE;
20import static android.content.pm.PackageManager.FEATURE_LEANBACK;
21import static android.content.pm.PackageManager.FEATURE_TELEVISION;
22import static android.service.notification.NotificationListenerService
23        .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
24import static android.service.notification.NotificationListenerService
25        .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
26import static android.service.notification.NotificationListenerService
27        .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
28import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
29import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
30import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
31import static android.service.notification.NotificationListenerService.REASON_CANCEL;
32import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
33import static android.service.notification.NotificationListenerService.REASON_CLICK;
34import static android.service.notification.NotificationListenerService.REASON_ERROR;
35import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
36import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
37import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
38import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
39import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
40import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
41import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
42import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
43import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
44import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
45import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
46import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
47import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
48import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
49import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
50import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
51import static android.service.notification.NotificationListenerService.TRIM_FULL;
52import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
53
54import static android.view.Display.DEFAULT_DISPLAY;
55import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
56import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
57
58import android.Manifest;
59import android.annotation.Nullable;
60import android.app.ActivityManager;
61import android.app.ActivityManagerInternal;
62import android.app.AlarmManager;
63import android.app.AppGlobals;
64import android.app.AppOpsManager;
65import android.app.AutomaticZenRule;
66import android.app.NotificationChannelGroup;
67import android.app.backup.BackupManager;
68import android.app.IActivityManager;
69import android.app.INotificationManager;
70import android.app.ITransientNotification;
71import android.app.Notification;
72import android.app.NotificationChannel;
73import android.app.NotificationManager.Policy;
74import android.app.NotificationManager;
75import android.app.PendingIntent;
76import android.app.StatusBarManager;
77import android.app.usage.UsageEvents;
78import android.app.usage.UsageStatsManagerInternal;
79import android.companion.ICompanionDeviceManager;
80import android.content.BroadcastReceiver;
81import android.content.ComponentName;
82import android.content.ContentResolver;
83import android.content.Context;
84import android.content.Intent;
85import android.content.IntentFilter;
86import android.content.pm.ApplicationInfo;
87import android.content.pm.IPackageManager;
88import android.content.pm.PackageInfo;
89import android.content.pm.PackageManager;
90import android.content.pm.PackageManager.NameNotFoundException;
91import android.content.pm.ParceledListSlice;
92import android.content.pm.UserInfo;
93import android.content.res.Resources;
94import android.database.ContentObserver;
95import android.media.AudioManager;
96import android.media.AudioManagerInternal;
97import android.media.IRingtonePlayer;
98import android.net.Uri;
99import android.os.Binder;
100import android.os.Build;
101import android.os.Bundle;
102import android.os.Environment;
103import android.os.Handler;
104import android.os.HandlerThread;
105import android.os.IBinder;
106import android.os.IInterface;
107import android.os.Looper;
108import android.os.Message;
109import android.os.Process;
110import android.os.RemoteException;
111import android.os.ServiceManager;
112import android.os.SystemClock;
113import android.os.SystemProperties;
114import android.os.UserHandle;
115import android.os.UserManager;
116import android.os.Vibrator;
117import android.os.VibrationEffect;
118import android.provider.Settings;
119import android.service.notification.Adjustment;
120import android.service.notification.Condition;
121import android.service.notification.IConditionProvider;
122import android.service.notification.INotificationListener;
123import android.service.notification.IStatusBarNotificationHolder;
124import android.service.notification.NotificationAssistantService;
125import android.service.notification.NotificationListenerService;
126import android.service.notification.NotificationRankingUpdate;
127import android.service.notification.NotificationRecordProto;
128import android.service.notification.NotificationServiceDumpProto;
129import android.service.notification.NotificationServiceProto;
130import android.service.notification.SnoozeCriterion;
131import android.service.notification.StatusBarNotification;
132import android.service.notification.ZenModeConfig;
133import android.service.notification.ZenModeProto;
134import android.telephony.PhoneStateListener;
135import android.telephony.TelephonyManager;
136import android.text.TextUtils;
137import android.util.ArrayMap;
138import android.util.ArraySet;
139import android.util.AtomicFile;
140import android.util.Log;
141import android.util.Slog;
142import android.util.SparseArray;
143import android.util.Xml;
144import android.util.proto.ProtoOutputStream;
145import android.view.WindowManagerInternal;
146import android.view.accessibility.AccessibilityEvent;
147import android.view.accessibility.AccessibilityManager;
148import android.widget.Toast;
149
150import com.android.internal.R;
151import com.android.internal.annotations.VisibleForTesting;
152import com.android.internal.logging.MetricsLogger;
153import com.android.internal.logging.nano.MetricsProto;
154import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
155import com.android.internal.statusbar.NotificationVisibility;
156import com.android.internal.util.ArrayUtils;
157import com.android.internal.util.DumpUtils;
158import com.android.internal.util.FastXmlSerializer;
159import com.android.internal.util.Preconditions;
160import com.android.server.DeviceIdleController;
161import com.android.server.EventLogTags;
162import com.android.server.LocalServices;
163import com.android.server.SystemService;
164import com.android.server.lights.Light;
165import com.android.server.lights.LightsManager;
166import com.android.server.notification.ManagedServices.ManagedServiceInfo;
167import com.android.server.policy.PhoneWindowManager;
168import com.android.server.statusbar.StatusBarManagerInternal;
169import com.android.server.notification.ManagedServices.UserProfiles;
170
171import libcore.io.IoUtils;
172
173import org.json.JSONException;
174import org.json.JSONObject;
175import org.xmlpull.v1.XmlPullParser;
176import org.xmlpull.v1.XmlPullParserException;
177import org.xmlpull.v1.XmlSerializer;
178
179import java.io.ByteArrayInputStream;
180import java.io.ByteArrayOutputStream;
181import java.io.File;
182import java.io.FileDescriptor;
183import java.io.FileInputStream;
184import java.io.FileNotFoundException;
185import java.io.FileOutputStream;
186import java.io.IOException;
187import java.io.InputStream;
188import java.io.OutputStream;
189import java.io.PrintWriter;
190import java.nio.charset.StandardCharsets;
191import java.util.ArrayDeque;
192import java.util.ArrayList;
193import java.util.Arrays;
194import java.util.Iterator;
195import java.util.List;
196import java.util.Map;
197import java.util.Map.Entry;
198import java.util.Objects;
199import java.util.concurrent.TimeUnit;
200
201/** {@hide} */
202public class NotificationManagerService extends SystemService {
203    static final String TAG = "NotificationService";
204    static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
205    public static final boolean ENABLE_CHILD_NOTIFICATIONS
206            = SystemProperties.getBoolean("debug.child_notifs", true);
207
208    static final int MAX_PACKAGE_NOTIFICATIONS = 50;
209    static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f;
210
211    // message codes
212    static final int MESSAGE_TIMEOUT = 2;
213    static final int MESSAGE_SAVE_POLICY_FILE = 3;
214    static final int MESSAGE_SEND_RANKING_UPDATE = 4;
215    static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
216    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
217
218    // ranking thread messages
219    private static final int MESSAGE_RECONSIDER_RANKING = 1000;
220    private static final int MESSAGE_RANKING_SORT = 1001;
221
222    static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
223    static final int SHORT_DELAY = 2000; // 2 seconds
224
225    static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
226
227    static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
228
229    static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
230
231    static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
232
233    static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
234    static final boolean ENABLE_BLOCKED_TOASTS = true;
235
236    // When #matchesCallFilter is called from the ringer, wait at most
237    // 3s to resolve the contacts. This timeout is required since
238    // ContactsProvider might take a long time to start up.
239    //
240    // Return STARRED_CONTACT when the timeout is hit in order to avoid
241    // missed calls in ZEN mode "Important".
242    static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
243    static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
244            ValidateNotificationPeople.STARRED_CONTACT;
245
246    /** notification_enqueue status value for a newly enqueued notification. */
247    private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
248
249    /** notification_enqueue status value for an existing notification. */
250    private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
251
252    /** notification_enqueue status value for an ignored notification. */
253    private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
254    private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
255
256    private static final long DELAY_FOR_ASSISTANT_TIME = 100;
257
258    private static final String ACTION_NOTIFICATION_TIMEOUT =
259            NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
260    private static final int REQUEST_CODE_TIMEOUT = 1;
261    private static final String SCHEME_TIMEOUT = "timeout";
262    private static final String EXTRA_KEY = "key";
263
264    private IActivityManager mAm;
265    private IPackageManager mPackageManager;
266    private PackageManager mPackageManagerClient;
267    AudioManager mAudioManager;
268    AudioManagerInternal mAudioManagerInternal;
269    @Nullable StatusBarManagerInternal mStatusBar;
270    Vibrator mVibrator;
271    private WindowManagerInternal mWindowManagerInternal;
272    private AlarmManager mAlarmManager;
273    private ICompanionDeviceManager mCompanionManager;
274
275    final IBinder mForegroundToken = new Binder();
276    private Handler mHandler;
277    private final HandlerThread mRankingThread = new HandlerThread("ranker",
278            Process.THREAD_PRIORITY_BACKGROUND);
279
280    private Light mNotificationLight;
281    Light mAttentionLight;
282
283    private long[] mFallbackVibrationPattern;
284    private boolean mUseAttentionLight;
285    boolean mSystemReady;
286
287    private boolean mDisableNotificationEffects;
288    private int mCallState;
289    private String mSoundNotificationKey;
290    private String mVibrateNotificationKey;
291
292    private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
293            new SparseArray<ArraySet<ManagedServiceInfo>>();
294    private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
295    private int mListenerHints;  // right now, all hints are global
296    private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
297
298    // for enabling and disabling notification pulse behavior
299    private boolean mScreenOn = true;
300    private boolean mInCall = false;
301    private boolean mNotificationPulseEnabled;
302
303    // used as a mutex for access to all active notifications & listeners
304    final Object mNotificationLock = new Object();
305    final ArrayList<NotificationRecord> mNotificationList =
306            new ArrayList<NotificationRecord>();
307    final ArrayMap<String, NotificationRecord> mNotificationsByKey =
308            new ArrayMap<String, NotificationRecord>();
309    final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
310    final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
311    final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
312    final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
313    final PolicyAccess mPolicyAccess = new PolicyAccess();
314
315    // The last key in this list owns the hardware.
316    ArrayList<String> mLights = new ArrayList<>();
317
318    private AppOpsManager mAppOps;
319    private UsageStatsManagerInternal mAppUsageStats;
320
321    private Archive mArchive;
322
323    // Persistent storage for notification policy
324    private AtomicFile mPolicyFile;
325
326    private static final int DB_VERSION = 1;
327
328    private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
329    private static final String ATTR_VERSION = "version";
330
331    private RankingHelper mRankingHelper;
332
333    private final UserProfiles mUserProfiles = new UserProfiles();
334    private NotificationListeners mListeners;
335    private NotificationAssistants mNotificationAssistants;
336    private ConditionProviders mConditionProviders;
337    private NotificationUsageStats mUsageStats;
338
339    private static final int MY_UID = Process.myUid();
340    private static final int MY_PID = Process.myPid();
341    private RankingHandler mRankingHandler;
342    private long mLastOverRateLogTime;
343    private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
344
345    private SnoozeHelper mSnoozeHelper;
346    private GroupHelper mGroupHelper;
347    private boolean mIsTelevision;
348
349    private static class Archive {
350        final int mBufferSize;
351        final ArrayDeque<StatusBarNotification> mBuffer;
352
353        public Archive(int size) {
354            mBufferSize = size;
355            mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
356        }
357
358        public String toString() {
359            final StringBuilder sb = new StringBuilder();
360            final int N = mBuffer.size();
361            sb.append("Archive (");
362            sb.append(N);
363            sb.append(" notification");
364            sb.append((N==1)?")":"s)");
365            return sb.toString();
366        }
367
368        public void record(StatusBarNotification nr) {
369            if (mBuffer.size() == mBufferSize) {
370                mBuffer.removeFirst();
371            }
372
373            // We don't want to store the heavy bits of the notification in the archive,
374            // but other clients in the system process might be using the object, so we
375            // store a (lightened) copy.
376            mBuffer.addLast(nr.cloneLight());
377        }
378
379        public Iterator<StatusBarNotification> descendingIterator() {
380            return mBuffer.descendingIterator();
381        }
382
383        public StatusBarNotification[] getArray(int count) {
384            if (count == 0) count = mBufferSize;
385            final StatusBarNotification[] a
386                    = new StatusBarNotification[Math.min(count, mBuffer.size())];
387            Iterator<StatusBarNotification> iter = descendingIterator();
388            int i=0;
389            while (iter.hasNext() && i < count) {
390                a[i++] = iter.next();
391            }
392            return a;
393        }
394
395    }
396
397    private void readPolicyXml(InputStream stream, boolean forRestore)
398            throws XmlPullParserException, NumberFormatException, IOException {
399        final XmlPullParser parser = Xml.newPullParser();
400        parser.setInput(stream, StandardCharsets.UTF_8.name());
401
402        while (parser.next() != END_DOCUMENT) {
403            mZenModeHelper.readXml(parser, forRestore);
404            mRankingHelper.readXml(parser, forRestore);
405        }
406    }
407
408    private void loadPolicyFile() {
409        if (DBG) Slog.d(TAG, "loadPolicyFile");
410        synchronized (mPolicyFile) {
411
412            FileInputStream infile = null;
413            try {
414                infile = mPolicyFile.openRead();
415                readPolicyXml(infile, false /*forRestore*/);
416            } catch (FileNotFoundException e) {
417                // No data yet
418            } catch (IOException e) {
419                Log.wtf(TAG, "Unable to read notification policy", e);
420            } catch (NumberFormatException e) {
421                Log.wtf(TAG, "Unable to parse notification policy", e);
422            } catch (XmlPullParserException e) {
423                Log.wtf(TAG, "Unable to parse notification policy", e);
424            } finally {
425                IoUtils.closeQuietly(infile);
426            }
427        }
428    }
429
430    public void savePolicyFile() {
431        mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
432        mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
433    }
434
435    private void handleSavePolicyFile() {
436        if (DBG) Slog.d(TAG, "handleSavePolicyFile");
437        synchronized (mPolicyFile) {
438            final FileOutputStream stream;
439            try {
440                stream = mPolicyFile.startWrite();
441            } catch (IOException e) {
442                Slog.w(TAG, "Failed to save policy file", e);
443                return;
444            }
445
446            try {
447                writePolicyXml(stream, false /*forBackup*/);
448                mPolicyFile.finishWrite(stream);
449            } catch (IOException e) {
450                Slog.w(TAG, "Failed to save policy file, restoring backup", e);
451                mPolicyFile.failWrite(stream);
452            }
453        }
454        BackupManager.dataChanged(getContext().getPackageName());
455    }
456
457    private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
458        final XmlSerializer out = new FastXmlSerializer();
459        out.setOutput(stream, StandardCharsets.UTF_8.name());
460        out.startDocument(null, true);
461        out.startTag(null, TAG_NOTIFICATION_POLICY);
462        out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
463        mZenModeHelper.writeXml(out, forBackup);
464        mRankingHelper.writeXml(out, forBackup);
465        out.endTag(null, TAG_NOTIFICATION_POLICY);
466        out.endDocument();
467    }
468
469    /** Use this when you actually want to post a notification or toast.
470     *
471     * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
472     */
473    private boolean noteNotificationOp(String pkg, int uid) {
474        if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
475                != AppOpsManager.MODE_ALLOWED) {
476            Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
477            return false;
478        }
479        return true;
480    }
481
482    /** Use this to check if a package can post a notification or toast. */
483    private boolean checkNotificationOp(String pkg, int uid) {
484        return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
485                == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
486    }
487
488    private static final class ToastRecord
489    {
490        final int pid;
491        final String pkg;
492        final ITransientNotification callback;
493        int duration;
494        Binder token;
495
496        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
497                    Binder token) {
498            this.pid = pid;
499            this.pkg = pkg;
500            this.callback = callback;
501            this.duration = duration;
502            this.token = token;
503        }
504
505        void update(int duration) {
506            this.duration = duration;
507        }
508
509        void dump(PrintWriter pw, String prefix, DumpFilter filter) {
510            if (filter != null && !filter.matches(pkg)) return;
511            pw.println(prefix + this);
512        }
513
514        @Override
515        public final String toString()
516        {
517            return "ToastRecord{"
518                + Integer.toHexString(System.identityHashCode(this))
519                + " pkg=" + pkg
520                + " callback=" + callback
521                + " duration=" + duration;
522        }
523    }
524
525    private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
526
527        @Override
528        public void onSetDisabled(int status) {
529            synchronized (mNotificationLock) {
530                mDisableNotificationEffects =
531                        (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
532                if (disableNotificationEffects(null) != null) {
533                    // cancel whatever's going on
534                    long identity = Binder.clearCallingIdentity();
535                    try {
536                        final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
537                        if (player != null) {
538                            player.stopAsync();
539                        }
540                    } catch (RemoteException e) {
541                    } finally {
542                        Binder.restoreCallingIdentity(identity);
543                    }
544
545                    identity = Binder.clearCallingIdentity();
546                    try {
547                        mVibrator.cancel();
548                    } finally {
549                        Binder.restoreCallingIdentity(identity);
550                    }
551                }
552            }
553        }
554
555        @Override
556        public void onClearAll(int callingUid, int callingPid, int userId) {
557            synchronized (mNotificationLock) {
558                cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
559                        /*includeCurrentProfiles*/ true);
560            }
561        }
562
563        @Override
564        public void onNotificationClick(int callingUid, int callingPid, String key) {
565            synchronized (mNotificationLock) {
566                NotificationRecord r = mNotificationsByKey.get(key);
567                if (r == null) {
568                    Log.w(TAG, "No notification with key: " + key);
569                    return;
570                }
571                final long now = System.currentTimeMillis();
572                MetricsLogger.action(r.getLogMaker(now)
573                        .setCategory(MetricsEvent.NOTIFICATION_ITEM)
574                        .setType(MetricsEvent.TYPE_ACTION));
575                EventLogTags.writeNotificationClicked(key,
576                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
577
578                StatusBarNotification sbn = r.sbn;
579                cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
580                        sbn.getId(), Notification.FLAG_AUTO_CANCEL,
581                        Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
582                        REASON_CLICK, null);
583            }
584        }
585
586        @Override
587        public void onNotificationActionClick(int callingUid, int callingPid, String key,
588                int actionIndex) {
589            synchronized (mNotificationLock) {
590                NotificationRecord r = mNotificationsByKey.get(key);
591                if (r == null) {
592                    Log.w(TAG, "No notification with key: " + key);
593                    return;
594                }
595                final long now = System.currentTimeMillis();
596                MetricsLogger.action(r.getLogMaker(now)
597                        .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
598                        .setType(MetricsEvent.TYPE_ACTION)
599                        .setSubtype(actionIndex));
600                EventLogTags.writeNotificationActionClicked(key, actionIndex,
601                        r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
602                // TODO: Log action click via UsageStats.
603            }
604        }
605
606        @Override
607        public void onNotificationClear(int callingUid, int callingPid,
608                String pkg, String tag, int id, int userId) {
609            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
610                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
611                    true, userId, REASON_CANCEL, null);
612        }
613
614        @Override
615        public void onPanelRevealed(boolean clearEffects, int items) {
616            MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
617            MetricsLogger.histogram(getContext(), "notification_load", items);
618            EventLogTags.writeNotificationPanelRevealed(items);
619            if (clearEffects) {
620                clearEffects();
621            }
622        }
623
624        @Override
625        public void onPanelHidden() {
626            MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
627            EventLogTags.writeNotificationPanelHidden();
628        }
629
630        @Override
631        public void clearEffects() {
632            synchronized (mNotificationLock) {
633                if (DBG) Slog.d(TAG, "clearEffects");
634                clearSoundLocked();
635                clearVibrateLocked();
636                clearLightsLocked();
637            }
638        }
639
640        @Override
641        public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
642                int uid, int initialPid, String message, int userId) {
643            Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
644                    + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
645            cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
646                    REASON_ERROR, null);
647            long ident = Binder.clearCallingIdentity();
648            try {
649                ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
650                        "Bad notification posted from package " + pkg
651                        + ": " + message);
652            } catch (RemoteException e) {
653            }
654            Binder.restoreCallingIdentity(ident);
655        }
656
657        @Override
658        public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
659                NotificationVisibility[] noLongerVisibleKeys) {
660            synchronized (mNotificationLock) {
661                for (NotificationVisibility nv : newlyVisibleKeys) {
662                    NotificationRecord r = mNotificationsByKey.get(nv.key);
663                    if (r == null) continue;
664                    r.setVisibility(true, nv.rank);
665                    nv.recycle();
666                }
667                // Note that we might receive this event after notifications
668                // have already left the system, e.g. after dismissing from the
669                // shade. Hence not finding notifications in
670                // mNotificationsByKey is not an exceptional condition.
671                for (NotificationVisibility nv : noLongerVisibleKeys) {
672                    NotificationRecord r = mNotificationsByKey.get(nv.key);
673                    if (r == null) continue;
674                    r.setVisibility(false, nv.rank);
675                    nv.recycle();
676                }
677            }
678        }
679
680        @Override
681        public void onNotificationExpansionChanged(String key,
682                boolean userAction, boolean expanded) {
683            synchronized (mNotificationLock) {
684                NotificationRecord r = mNotificationsByKey.get(key);
685                if (r != null) {
686                    r.stats.onExpansionChanged(userAction, expanded);
687                    final long now = System.currentTimeMillis();
688                    MetricsLogger.action(r.getLogMaker(now)
689                            .setCategory(MetricsEvent.NOTIFICATION_ITEM)
690                            .setType(MetricsEvent.TYPE_DETAIL));
691                    EventLogTags.writeNotificationExpansion(key,
692                            userAction ? 1 : 0, expanded ? 1 : 0,
693                            r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
694                }
695            }
696        }
697    };
698
699    private void clearSoundLocked() {
700        mSoundNotificationKey = null;
701        long identity = Binder.clearCallingIdentity();
702        try {
703            final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
704            if (player != null) {
705                player.stopAsync();
706            }
707        } catch (RemoteException e) {
708        } finally {
709            Binder.restoreCallingIdentity(identity);
710        }
711    }
712
713    private void clearVibrateLocked() {
714        mVibrateNotificationKey = null;
715        long identity = Binder.clearCallingIdentity();
716        try {
717            mVibrator.cancel();
718        } finally {
719            Binder.restoreCallingIdentity(identity);
720        }
721    }
722
723    private void clearLightsLocked() {
724        // light
725        mLights.clear();
726        updateLightsLocked();
727    }
728
729    private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
730        @Override
731        public void onReceive(Context context, Intent intent) {
732            String action = intent.getAction();
733            if (action == null) {
734                return;
735            }
736            if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
737                final NotificationRecord record;
738                synchronized (mNotificationLock) {
739                    record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
740                }
741                if (record != null) {
742                    cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
743                            record.sbn.getPackageName(), record.sbn.getTag(),
744                            record.sbn.getId(), 0,
745                            Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
746                            REASON_TIMEOUT, null);
747                }
748            }
749        }
750    };
751
752    private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
753        @Override
754        public void onReceive(Context context, Intent intent) {
755            String action = intent.getAction();
756            if (action == null) {
757                return;
758            }
759
760            boolean queryRestart = false;
761            boolean queryRemove = false;
762            boolean packageChanged = false;
763            boolean cancelNotifications = true;
764            int reason = REASON_PACKAGE_CHANGED;
765
766            if (action.equals(Intent.ACTION_PACKAGE_ADDED)
767                    || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
768                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
769                    || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
770                    || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
771                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
772                    || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
773                int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
774                        UserHandle.USER_ALL);
775                String pkgList[] = null;
776                int uidList[] = null;
777                boolean removingPackage = queryRemove &&
778                        !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
779                if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
780                if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
781                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
782                    uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
783                } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
784                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
785                    reason = REASON_PACKAGE_SUSPENDED;
786                } else if (queryRestart) {
787                    pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
788                    uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
789                } else {
790                    Uri uri = intent.getData();
791                    if (uri == null) {
792                        return;
793                    }
794                    String pkgName = uri.getSchemeSpecificPart();
795                    if (pkgName == null) {
796                        return;
797                    }
798                    if (packageChanged) {
799                        // We cancel notifications for packages which have just been disabled
800                        try {
801                            final int enabled = mPackageManager.getApplicationEnabledSetting(
802                                    pkgName,
803                                    changeUserId != UserHandle.USER_ALL ? changeUserId :
804                                            UserHandle.USER_SYSTEM);
805                            if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
806                                    || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
807                                cancelNotifications = false;
808                            }
809                        } catch (IllegalArgumentException e) {
810                            // Package doesn't exist; probably racing with uninstall.
811                            // cancelNotifications is already true, so nothing to do here.
812                            if (DBG) {
813                                Slog.i(TAG, "Exception trying to look up app enabled setting", e);
814                            }
815                        } catch (RemoteException e) {
816                            // Failed to talk to PackageManagerService Should never happen!
817                        }
818                    }
819                    pkgList = new String[]{pkgName};
820                    uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
821                }
822                if (pkgList != null && (pkgList.length > 0)) {
823                    for (String pkgName : pkgList) {
824                        if (cancelNotifications) {
825                            cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
826                                    !queryRestart, changeUserId, reason, null);
827                        }
828                    }
829                }
830                mListeners.onPackagesChanged(removingPackage, pkgList);
831                mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
832                mConditionProviders.onPackagesChanged(removingPackage, pkgList);
833                mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
834                savePolicyFile();
835            }
836        }
837    };
838
839    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
840        @Override
841        public void onReceive(Context context, Intent intent) {
842            String action = intent.getAction();
843
844            if (action.equals(Intent.ACTION_SCREEN_ON)) {
845                // Keep track of screen on/off state, but do not turn off the notification light
846                // until user passes through the lock screen or views the notification.
847                mScreenOn = true;
848                updateNotificationPulse();
849            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
850                mScreenOn = false;
851                updateNotificationPulse();
852            } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
853                mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
854                        .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
855                updateNotificationPulse();
856            } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
857                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
858                if (userHandle >= 0) {
859                    cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
860                            REASON_USER_STOPPED, null);
861                }
862            } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
863                int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
864                if (userHandle >= 0) {
865                    cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
866                            REASON_PROFILE_TURNED_OFF, null);
867                }
868            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
869                // turn off LED when user passes through lock screen
870                mNotificationLight.turnOff();
871            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
872                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
873                // reload per-user settings
874                mSettingsObserver.update(null);
875                mUserProfiles.updateCache(context);
876                // Refresh managed services
877                mConditionProviders.onUserSwitched(user);
878                mListeners.onUserSwitched(user);
879                mNotificationAssistants.onUserSwitched(user);
880                mZenModeHelper.onUserSwitched(user);
881            } else if (action.equals(Intent.ACTION_USER_ADDED)) {
882                mUserProfiles.updateCache(context);
883            } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
884                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
885                mZenModeHelper.onUserRemoved(user);
886            } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
887                final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
888                mConditionProviders.onUserUnlocked(user);
889                mListeners.onUserUnlocked(user);
890                mNotificationAssistants.onUserUnlocked(user);
891                mZenModeHelper.onUserUnlocked(user);
892            }
893        }
894    };
895
896    private final class SettingsObserver extends ContentObserver {
897        private final Uri NOTIFICATION_LIGHT_PULSE_URI
898                = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
899        private final Uri NOTIFICATION_RATE_LIMIT_URI
900                = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
901
902        SettingsObserver(Handler handler) {
903            super(handler);
904        }
905
906        void observe() {
907            ContentResolver resolver = getContext().getContentResolver();
908            resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
909                    false, this, UserHandle.USER_ALL);
910            resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
911                    false, this, UserHandle.USER_ALL);
912            update(null);
913        }
914
915        @Override public void onChange(boolean selfChange, Uri uri) {
916            update(uri);
917        }
918
919        public void update(Uri uri) {
920            ContentResolver resolver = getContext().getContentResolver();
921            if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
922                boolean pulseEnabled = Settings.System.getInt(resolver,
923                            Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
924                if (mNotificationPulseEnabled != pulseEnabled) {
925                    mNotificationPulseEnabled = pulseEnabled;
926                    updateNotificationPulse();
927                }
928            }
929            if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
930                mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
931                            Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
932            }
933        }
934    }
935
936    private SettingsObserver mSettingsObserver;
937    private ZenModeHelper mZenModeHelper;
938
939    static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
940        int[] ar = r.getIntArray(resid);
941        if (ar == null) {
942            return def;
943        }
944        final int len = ar.length > maxlen ? maxlen : ar.length;
945        long[] out = new long[len];
946        for (int i=0; i<len; i++) {
947            out[i] = ar[i];
948        }
949        return out;
950    }
951
952    public NotificationManagerService(Context context) {
953        super(context);
954    }
955
956    // TODO - replace these methods with a single VisibleForTesting constructor
957    @VisibleForTesting
958    void setAudioManager(AudioManager audioMananger) {
959        mAudioManager = audioMananger;
960    }
961
962    @VisibleForTesting
963    void setVibrator(Vibrator vibrator) {
964        mVibrator = vibrator;
965    }
966
967    @VisibleForTesting
968    void setLights(Light light) {
969        mNotificationLight = light;
970        mAttentionLight = light;
971        mNotificationPulseEnabled = true;
972    }
973
974    @VisibleForTesting
975    void setScreenOn(boolean on) {
976        mScreenOn = on;
977    }
978
979    @VisibleForTesting
980    void addNotification(NotificationRecord r) {
981        mNotificationList.add(r);
982        mNotificationsByKey.put(r.sbn.getKey(), r);
983    }
984
985    @VisibleForTesting
986    void setSystemReady(boolean systemReady) {
987        mSystemReady = systemReady;
988    }
989
990    @VisibleForTesting
991    void setHandler(Handler handler) {
992        mHandler = handler;
993    }
994
995    @VisibleForTesting
996    void setFallbackVibrationPattern(long[] vibrationPattern) {
997        mFallbackVibrationPattern = vibrationPattern;
998    }
999
1000    @VisibleForTesting
1001    void setPackageManager(IPackageManager packageManager) {
1002        mPackageManager = packageManager;
1003    }
1004
1005    @VisibleForTesting
1006    void setRankingHelper(RankingHelper rankingHelper) {
1007        mRankingHelper = rankingHelper;
1008    }
1009
1010    @VisibleForTesting
1011    void setIsTelevision(boolean isTelevision) {
1012        mIsTelevision = isTelevision;
1013    }
1014
1015    // TODO: Tests should call onStart instead once the methods above are removed.
1016    @VisibleForTesting
1017    void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
1018            LightsManager lightsManager, NotificationListeners notificationListeners,
1019            ICompanionDeviceManager companionManager) {
1020        Resources resources = getContext().getResources();
1021        mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1022                Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1023                DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1024
1025        mAm = ActivityManager.getService();
1026        mPackageManager = packageManager;
1027        mPackageManagerClient = packageManagerClient;
1028        mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1029        mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
1030        mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
1031        mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
1032        mCompanionManager = companionManager;
1033
1034        mHandler = new WorkerHandler(looper);
1035        mRankingThread.start();
1036        String[] extractorNames;
1037        try {
1038            extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1039        } catch (Resources.NotFoundException e) {
1040            extractorNames = new String[0];
1041        }
1042        mUsageStats = new NotificationUsageStats(getContext());
1043        mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
1044        mRankingHelper = new RankingHelper(getContext(),
1045                getContext().getPackageManager(),
1046                mRankingHandler,
1047                mUsageStats,
1048                extractorNames);
1049        mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
1050        mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
1051        mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
1052            @Override
1053            public void onConfigChanged() {
1054                savePolicyFile();
1055            }
1056
1057            @Override
1058            void onZenModeChanged() {
1059                sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
1060                getContext().sendBroadcastAsUser(
1061                        new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1062                                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
1063                        UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
1064                synchronized (mNotificationLock) {
1065                    updateInterruptionFilterLocked();
1066                }
1067            }
1068
1069            @Override
1070            void onPolicyChanged() {
1071                sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1072            }
1073        });
1074        mSnoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1075            @Override
1076            public void repost(int userId, NotificationRecord r) {
1077                try {
1078                    if (DBG) {
1079                        Slog.d(TAG, "Reposting " + r.getKey());
1080                    }
1081                    enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1082                            r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1083                            r.sbn.getNotification(), new int[1], userId);
1084                } catch (Exception e) {
1085                    Slog.e(TAG, "Cannot un-snooze notification", e);
1086                }
1087            }
1088        }, mUserProfiles);
1089        mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
1090            @Override
1091            public void addAutoGroup(String key) {
1092                synchronized (mNotificationLock) {
1093                    addAutogroupKeyLocked(key);
1094                }
1095                mRankingHandler.requestSort(false);
1096            }
1097
1098            @Override
1099            public void removeAutoGroup(String key) {
1100                synchronized (mNotificationLock) {
1101                    removeAutogroupKeyLocked(key);
1102                }
1103                mRankingHandler.requestSort(false);
1104            }
1105
1106            @Override
1107            public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1108                createAutoGroupSummary(userId, pkg, triggeringKey);
1109            }
1110
1111            @Override
1112            public void removeAutoGroupSummary(int userId, String pkg) {
1113                synchronized (mNotificationLock) {
1114                    clearAutogroupSummaryLocked(userId, pkg);
1115                }
1116            }
1117        });
1118
1119        final File systemDir = new File(Environment.getDataDirectory(), "system");
1120        mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
1121
1122        syncBlockDb();
1123
1124        // This is a ManagedServices object that keeps track of the listeners.
1125        mListeners = notificationListeners;
1126
1127        // This is a MangedServices object that keeps track of the assistant.
1128        mNotificationAssistants = new NotificationAssistants();
1129
1130        mStatusBar = getLocalService(StatusBarManagerInternal.class);
1131        if (mStatusBar != null) {
1132            mStatusBar.setNotificationDelegate(mNotificationDelegate);
1133        }
1134
1135        mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1136        mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
1137
1138        mFallbackVibrationPattern = getLongArray(resources,
1139                R.array.config_notificationFallbackVibePattern,
1140                VIBRATE_PATTERN_MAXLEN,
1141                DEFAULT_VIBRATE_PATTERN);
1142
1143        mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1144
1145        // Don't start allowing notifications until the setup wizard has run once.
1146        // After that, including subsequent boots, init with notifications turned on.
1147        // This works on the first boot because the setup wizard will toggle this
1148        // flag at least once and we'll go back to 0 after that.
1149        if (0 == Settings.Global.getInt(getContext().getContentResolver(),
1150                    Settings.Global.DEVICE_PROVISIONED, 0)) {
1151            mDisableNotificationEffects = true;
1152        }
1153        mZenModeHelper.initZenMode();
1154        mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1155
1156        mUserProfiles.updateCache(getContext());
1157        listenForCallState();
1158
1159        // register for various Intents
1160        IntentFilter filter = new IntentFilter();
1161        filter.addAction(Intent.ACTION_SCREEN_ON);
1162        filter.addAction(Intent.ACTION_SCREEN_OFF);
1163        filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
1164        filter.addAction(Intent.ACTION_USER_PRESENT);
1165        filter.addAction(Intent.ACTION_USER_STOPPED);
1166        filter.addAction(Intent.ACTION_USER_SWITCHED);
1167        filter.addAction(Intent.ACTION_USER_ADDED);
1168        filter.addAction(Intent.ACTION_USER_REMOVED);
1169        filter.addAction(Intent.ACTION_USER_UNLOCKED);
1170        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
1171        getContext().registerReceiver(mIntentReceiver, filter);
1172
1173        IntentFilter pkgFilter = new IntentFilter();
1174        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
1175        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1176        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
1177        pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1178        pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1179        pkgFilter.addDataScheme("package");
1180        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1181                null);
1182
1183        IntentFilter suspendedPkgFilter = new IntentFilter();
1184        suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1185        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1186                suspendedPkgFilter, null, null);
1187
1188        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
1189        getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1190                null);
1191
1192        IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1193        timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1194        getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1195
1196        mSettingsObserver = new SettingsObserver(mHandler);
1197
1198        mArchive = new Archive(resources.getInteger(
1199                R.integer.config_notificationServiceArchiveSize));
1200
1201        mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1202                || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1203    }
1204
1205    @Override
1206    public void onStart() {
1207        init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
1208                getLocalService(LightsManager.class), new NotificationListeners(),
1209                null);
1210        publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1211        publishLocalService(NotificationManagerInternal.class, mInternalService);
1212    }
1213
1214    private void sendRegisteredOnlyBroadcast(String action) {
1215        getContext().sendBroadcastAsUser(new Intent(action)
1216                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1217    }
1218
1219    /**
1220     * Make sure the XML config and the the AppOps system agree about blocks.
1221     */
1222    private void syncBlockDb() {
1223        loadPolicyFile();
1224
1225        // sync bans from ranker into app opps
1226        Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1227        for(Entry<Integer, String> ban : packageBans.entrySet()) {
1228            final int uid = ban.getKey();
1229            final String packageName = ban.getValue();
1230            setNotificationsEnabledForPackageImpl(packageName, uid, false);
1231        }
1232
1233        // sync bans from app opps into ranker
1234        packageBans.clear();
1235        for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1236            final int userId = user.getUserHandle().getIdentifier();
1237            final PackageManager packageManager = getContext().getPackageManager();
1238            List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1239            final int packageCount = packages.size();
1240            for (int p = 0; p < packageCount; p++) {
1241                final String packageName = packages.get(p).packageName;
1242                try {
1243                    final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1244                    if (!checkNotificationOp(packageName, uid)) {
1245                        packageBans.put(uid, packageName);
1246                    }
1247                } catch (NameNotFoundException e) {
1248                    // forget you
1249                }
1250            }
1251        }
1252        for (Entry<Integer, String> ban : packageBans.entrySet()) {
1253            mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1254        }
1255
1256        savePolicyFile();
1257    }
1258
1259    @Override
1260    public void onBootPhase(int phase) {
1261        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1262            // no beeping until we're basically done booting
1263            mSystemReady = true;
1264
1265            // Grab our optional AudioService
1266            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
1267            mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
1268            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
1269            mZenModeHelper.onSystemReady();
1270        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1271            // This observer will force an update when observe is called, causing us to
1272            // bind to listener services.
1273            mSettingsObserver.observe();
1274            mListeners.onBootPhaseAppsCanStart();
1275            mNotificationAssistants.onBootPhaseAppsCanStart();
1276            mConditionProviders.onBootPhaseAppsCanStart();
1277        }
1278    }
1279
1280    void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1281        Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
1282
1283        mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1284                enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
1285
1286        // Now, cancel any outstanding notifications that are part of a just-disabled app
1287        if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
1288            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1289                    UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1290        }
1291    }
1292
1293    private void updateListenerHintsLocked() {
1294        final int hints = calculateHints();
1295        if (hints == mListenerHints) return;
1296        ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
1297        mListenerHints = hints;
1298        scheduleListenerHintsChanged(hints);
1299    }
1300
1301    private void updateEffectsSuppressorLocked() {
1302        final long updatedSuppressedEffects = calculateSuppressedEffects();
1303        if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1304        final List<ComponentName> suppressors = getSuppressors();
1305        ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1306        mEffectsSuppressors = suppressors;
1307        mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
1308        sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
1309    }
1310
1311    private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1312            boolean fromListener) {
1313        if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1314            // cancel
1315            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1316                    UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1317                    null);
1318        }
1319        mRankingHelper.updateNotificationChannel(pkg, uid, channel);
1320
1321        final NotificationChannel modifiedChannel =
1322                mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
1323
1324        if (!fromListener) {
1325            mListeners.notifyNotificationChannelChanged(
1326                    pkg, UserHandle.getUserHandleForUid(uid),
1327                    modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
1328        }
1329
1330        synchronized (mNotificationLock) {
1331            final int N = mNotificationList.size();
1332            for (int i = N - 1; i >= 0; --i) {
1333                NotificationRecord r = mNotificationList.get(i);
1334                if (r.sbn.getPackageName().equals(pkg)
1335                        && r.sbn.getUid() == uid
1336                        && channel.getId() != null
1337                        && channel.getId().equals(r.getChannel().getId())) {
1338                    r.updateNotificationChannel(modifiedChannel);
1339                }
1340            }
1341        }
1342        mRankingHandler.requestSort(true);
1343        savePolicyFile();
1344    }
1345
1346    private ArrayList<ComponentName> getSuppressors() {
1347        ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1348        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1349            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1350
1351            for (ManagedServiceInfo info : serviceInfoList) {
1352                names.add(info.component);
1353            }
1354        }
1355
1356        return names;
1357    }
1358
1359    private boolean removeDisabledHints(ManagedServiceInfo info) {
1360        return removeDisabledHints(info, 0);
1361    }
1362
1363    private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1364        boolean removed = false;
1365
1366        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1367            final int hint = mListenersDisablingEffects.keyAt(i);
1368            final ArraySet<ManagedServiceInfo> listeners =
1369                    mListenersDisablingEffects.valueAt(i);
1370
1371            if (hints == 0 || (hint & hints) == hint) {
1372                removed = removed || listeners.remove(info);
1373            }
1374        }
1375
1376        return removed;
1377    }
1378
1379    private void addDisabledHints(ManagedServiceInfo info, int hints) {
1380        if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1381            addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1382        }
1383
1384        if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1385            addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1386        }
1387
1388        if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1389            addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1390        }
1391    }
1392
1393    private void addDisabledHint(ManagedServiceInfo info, int hint) {
1394        if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1395            mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1396        }
1397
1398        ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1399        hintListeners.add(info);
1400    }
1401
1402    private int calculateHints() {
1403        int hints = 0;
1404        for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1405            int hint = mListenersDisablingEffects.keyAt(i);
1406            ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1407
1408            if (!serviceInfoList.isEmpty()) {
1409                hints |= hint;
1410            }
1411        }
1412
1413        return hints;
1414    }
1415
1416    private long calculateSuppressedEffects() {
1417        int hints = calculateHints();
1418        long suppressedEffects = 0;
1419
1420        if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1421            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1422        }
1423
1424        if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1425            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1426        }
1427
1428        if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1429            suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1430        }
1431
1432        return suppressedEffects;
1433    }
1434
1435    private void updateInterruptionFilterLocked() {
1436        int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1437        if (interruptionFilter == mInterruptionFilter) return;
1438        mInterruptionFilter = interruptionFilter;
1439        scheduleInterruptionFilterChanged(interruptionFilter);
1440    }
1441
1442    @VisibleForTesting
1443    INotificationManager getBinderService() {
1444        return INotificationManager.Stub.asInterface(mService);
1445    }
1446
1447    @VisibleForTesting
1448    NotificationManagerInternal getInternalService() {
1449        return mInternalService;
1450    }
1451
1452    private final IBinder mService = new INotificationManager.Stub() {
1453        // Toasts
1454        // ============================================================================
1455
1456        @Override
1457        public void enqueueToast(String pkg, ITransientNotification callback, int duration)
1458        {
1459            if (DBG) {
1460                Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1461                        + " duration=" + duration);
1462            }
1463
1464            if (pkg == null || callback == null) {
1465                Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1466                return ;
1467            }
1468
1469            final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
1470            final boolean isPackageSuspended =
1471                    isPackageSuspendedForUser(pkg, Binder.getCallingUid());
1472
1473            if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
1474                    || isPackageSuspended)) {
1475                if (!isSystemToast) {
1476                    Slog.e(TAG, "Suppressing toast from package " + pkg
1477                            + (isPackageSuspended
1478                                    ? " due to package suspended by administrator."
1479                                    : " by user request."));
1480                    return;
1481                }
1482            }
1483
1484            synchronized (mToastQueue) {
1485                int callingPid = Binder.getCallingPid();
1486                long callingId = Binder.clearCallingIdentity();
1487                try {
1488                    ToastRecord record;
1489                    int index = indexOfToastLocked(pkg, callback);
1490                    // If it's already in the queue, we update it in place, we don't
1491                    // move it to the end of the queue.
1492                    if (index >= 0) {
1493                        record = mToastQueue.get(index);
1494                        record.update(duration);
1495                    } else {
1496                        // Limit the number of toasts that any given package except the android
1497                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
1498                        if (!isSystemToast) {
1499                            int count = 0;
1500                            final int N = mToastQueue.size();
1501                            for (int i=0; i<N; i++) {
1502                                 final ToastRecord r = mToastQueue.get(i);
1503                                 if (r.pkg.equals(pkg)) {
1504                                     count++;
1505                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1506                                         Slog.e(TAG, "Package has already posted " + count
1507                                                + " toasts. Not showing more. Package=" + pkg);
1508                                         return;
1509                                     }
1510                                 }
1511                            }
1512                        }
1513
1514                        Binder token = new Binder();
1515                        mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
1516                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
1517                        mToastQueue.add(record);
1518                        index = mToastQueue.size() - 1;
1519                        keepProcessAliveIfNeededLocked(callingPid);
1520                    }
1521                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
1522                    // new or just been updated.  Call back and tell it to show itself.
1523                    // If the callback fails, this will remove it from the list, so don't
1524                    // assume that it's valid after this.
1525                    if (index == 0) {
1526                        showNextToastLocked();
1527                    }
1528                } finally {
1529                    Binder.restoreCallingIdentity(callingId);
1530                }
1531            }
1532        }
1533
1534        @Override
1535        public void cancelToast(String pkg, ITransientNotification callback) {
1536            Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1537
1538            if (pkg == null || callback == null) {
1539                Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1540                return ;
1541            }
1542
1543            synchronized (mToastQueue) {
1544                long callingId = Binder.clearCallingIdentity();
1545                try {
1546                    int index = indexOfToastLocked(pkg, callback);
1547                    if (index >= 0) {
1548                        cancelToastLocked(index);
1549                    } else {
1550                        Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1551                                + " callback=" + callback);
1552                    }
1553                } finally {
1554                    Binder.restoreCallingIdentity(callingId);
1555                }
1556            }
1557        }
1558
1559        @Override
1560        public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
1561                Notification notification, int[] idOut, int userId) throws RemoteException {
1562            enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
1563                    Binder.getCallingPid(), tag, id, notification, idOut, userId);
1564        }
1565
1566        @Override
1567        public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
1568            checkCallerIsSystemOrSameApp(pkg);
1569            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1570                    Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1571            // Don't allow client applications to cancel foreground service notis or autobundled
1572            // summaries.
1573            cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
1574                    (Binder.getCallingUid() == Process.SYSTEM_UID
1575                            ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1576                            | (Binder.getCallingUid() == Process.SYSTEM_UID
1577                            ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
1578                    REASON_APP_CANCEL, null);
1579        }
1580
1581        @Override
1582        public void cancelAllNotifications(String pkg, int userId) {
1583            checkCallerIsSystemOrSameApp(pkg);
1584
1585            userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1586                    Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1587
1588            // Calling from user space, don't allow the canceling of actively
1589            // running foreground services.
1590            cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1591                    pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
1592                    REASON_APP_CANCEL_ALL, null);
1593        }
1594
1595        @Override
1596        public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
1597            checkCallerIsSystem();
1598
1599            setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1600            mRankingHelper.setEnabled(pkg, uid, enabled);
1601            savePolicyFile();
1602        }
1603
1604        /**
1605         * Use this when you just want to know if notifications are OK for this package.
1606         */
1607        @Override
1608        public boolean areNotificationsEnabled(String pkg) {
1609            return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1610        }
1611
1612        /**
1613         * Use this when you just want to know if notifications are OK for this package.
1614         */
1615        @Override
1616        public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
1617            checkCallerIsSystemOrSameApp(pkg);
1618            return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
1619                    == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
1620        }
1621
1622        @Override
1623        public int getPackageImportance(String pkg) {
1624            checkCallerIsSystemOrSameApp(pkg);
1625            return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
1626        }
1627
1628        @Override
1629        public boolean canShowBadge(String pkg, int uid) {
1630            checkCallerIsSystem();
1631            return mRankingHelper.canShowBadge(pkg, uid);
1632        }
1633
1634        @Override
1635        public void setShowBadge(String pkg, int uid, boolean showBadge) {
1636            checkCallerIsSystem();
1637            mRankingHelper.setShowBadge(pkg, uid, showBadge);
1638            savePolicyFile();
1639        }
1640
1641        @Override
1642        public void createNotificationChannelGroups(String pkg,
1643                ParceledListSlice channelGroupList) throws RemoteException {
1644            checkCallerIsSystemOrSameApp(pkg);
1645            List<NotificationChannelGroup> groups = channelGroupList.getList();
1646            final int groupSize = groups.size();
1647            for (int i = 0; i < groupSize; i++) {
1648                final NotificationChannelGroup group = groups.get(i);
1649                Preconditions.checkNotNull(group, "group in list is null");
1650                mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1651                        true /* fromTargetApp */);
1652                mListeners.notifyNotificationChannelGroupChanged(pkg,
1653                        UserHandle.of(UserHandle.getCallingUserId()), group,
1654                        NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1655            }
1656            savePolicyFile();
1657        }
1658
1659        private void createNotificationChannelsImpl(String pkg, int uid,
1660                ParceledListSlice channelsList) {
1661            List<NotificationChannel> channels = channelsList.getList();
1662            final int channelsSize = channels.size();
1663            for (int i = 0; i < channelsSize; i++) {
1664                final NotificationChannel channel = channels.get(i);
1665                Preconditions.checkNotNull(channel, "channel in list is null");
1666                mRankingHelper.createNotificationChannel(pkg, uid, channel,
1667                        true /* fromTargetApp */);
1668                mListeners.notifyNotificationChannelChanged(pkg,
1669                        UserHandle.getUserHandleForUid(uid),
1670                        mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1671                        NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1672            }
1673            savePolicyFile();
1674        }
1675
1676        @Override
1677        public void createNotificationChannels(String pkg,
1678                ParceledListSlice channelsList) throws RemoteException {
1679            checkCallerIsSystemOrSameApp(pkg);
1680            createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1681        }
1682
1683        @Override
1684        public void createNotificationChannelsForPackage(String pkg, int uid,
1685                ParceledListSlice channelsList) throws RemoteException {
1686            checkCallerIsSystem();
1687            createNotificationChannelsImpl(pkg, uid, channelsList);
1688        }
1689
1690        @Override
1691        public NotificationChannel getNotificationChannel(String pkg, String channelId) {
1692            checkCallerIsSystemOrSameApp(pkg);
1693            return mRankingHelper.getNotificationChannel(
1694                    pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
1695        }
1696
1697        @Override
1698        public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
1699                String channelId, boolean includeDeleted) {
1700            checkCallerIsSystem();
1701            return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
1702        }
1703
1704        @Override
1705        public void deleteNotificationChannel(String pkg, String channelId) {
1706            checkCallerIsSystemOrSameApp(pkg);
1707            final int callingUid = Binder.getCallingUid();
1708            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1709                throw new IllegalArgumentException("Cannot delete default channel");
1710            }
1711            cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
1712                    UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1713            mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1714            mListeners.notifyNotificationChannelChanged(pkg,
1715                    UserHandle.getUserHandleForUid(callingUid),
1716                    mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1717                    NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1718            savePolicyFile();
1719        }
1720
1721        @Override
1722        public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1723                String pkg) {
1724            checkCallerIsSystemOrSameApp(pkg);
1725            return new ParceledListSlice<>(new ArrayList(
1726                    mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1727        }
1728
1729        @Override
1730        public void deleteNotificationChannelGroup(String pkg, String groupId) {
1731            checkCallerIsSystemOrSameApp(pkg);
1732
1733            final int callingUid = Binder.getCallingUid();
1734            NotificationChannelGroup groupToDelete =
1735                    mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1736            if (groupToDelete != null) {
1737                List<NotificationChannel> deletedChannels =
1738                        mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1739                for (int i = 0; i < deletedChannels.size(); i++) {
1740                    final NotificationChannel deletedChannel = deletedChannels.get(i);
1741                    cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1742                            true,
1743                            UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1744                            null);
1745                    mListeners.notifyNotificationChannelChanged(pkg,
1746                            UserHandle.getUserHandleForUid(callingUid),
1747                            deletedChannel,
1748                            NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1749                }
1750                mListeners.notifyNotificationChannelGroupChanged(
1751                        pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1752                        NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1753                savePolicyFile();
1754            }
1755        }
1756
1757        @Override
1758        public void updateNotificationChannelForPackage(String pkg, int uid,
1759                NotificationChannel channel) {
1760            enforceSystemOrSystemUI("Caller not system or systemui");
1761            Preconditions.checkNotNull(channel);
1762            updateNotificationChannelInt(pkg, uid, channel, false);
1763        }
1764
1765        @Override
1766        public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
1767                int uid, boolean includeDeleted) {
1768            enforceSystemOrSystemUI("getNotificationChannelsForPackage");
1769            return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
1770        }
1771
1772        @Override
1773        public int getNumNotificationChannelsForPackage(String pkg, int uid,
1774                boolean includeDeleted) {
1775            enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1776            return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1777                    .getList().size();
1778        }
1779
1780        @Override
1781        public int getDeletedChannelCount(String pkg, int uid) {
1782            enforceSystemOrSystemUI("getDeletedChannelCount");
1783            return mRankingHelper.getDeletedChannelCount(pkg, uid);
1784        }
1785
1786        @Override
1787        public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1788                String pkg, int uid, boolean includeDeleted) {
1789            checkCallerIsSystem();
1790            return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1791        }
1792
1793        @Override
1794        public NotificationChannelGroup getNotificationChannelGroupForPackage(
1795                String groupId, String pkg, int uid) {
1796            enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1797            return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1798        }
1799
1800        @Override
1801        public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1802            checkCallerIsSystemOrSameApp(pkg);
1803            return mRankingHelper.getNotificationChannels(
1804                    pkg, Binder.getCallingUid(), false /* includeDeleted */);
1805        }
1806
1807        @Override
1808        public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
1809            checkCallerIsSystem();
1810
1811            // Cancel posted notifications
1812            cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1813                    UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1814
1815            // Listener & assistant
1816            mListeners.onPackagesChanged(true, new String[] {packageName});
1817            mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
1818
1819            // Zen
1820            mConditionProviders.onPackagesChanged(true, new String[] {packageName});
1821
1822            // Reset notification preferences
1823            if (!fromApp) {
1824                mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
1825                        new String[]{packageName}, new int[]{uid});
1826            }
1827
1828            savePolicyFile();
1829        }
1830
1831
1832        /**
1833         * System-only API for getting a list of current (i.e. not cleared) notifications.
1834         *
1835         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1836         * @returns A list of all the notifications, in natural order.
1837         */
1838        @Override
1839        public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1840            // enforce() will ensure the calling uid has the correct permission
1841            getContext().enforceCallingOrSelfPermission(
1842                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1843                    "NotificationManagerService.getActiveNotifications");
1844
1845            StatusBarNotification[] tmp = null;
1846            int uid = Binder.getCallingUid();
1847
1848            // noteOp will check to make sure the callingPkg matches the uid
1849            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1850                    == AppOpsManager.MODE_ALLOWED) {
1851                synchronized (mNotificationLock) {
1852                    tmp = new StatusBarNotification[mNotificationList.size()];
1853                    final int N = mNotificationList.size();
1854                    for (int i=0; i<N; i++) {
1855                        tmp[i] = mNotificationList.get(i).sbn;
1856                    }
1857                }
1858            }
1859            return tmp;
1860        }
1861
1862        /**
1863         * Public API for getting a list of current notifications for the calling package/uid.
1864         *
1865         * Note that since notification posting is done asynchronously, this will not return
1866         * notifications that are in the process of being posted.
1867         *
1868         * @returns A list of all the package's notifications, in natural order.
1869         */
1870        @Override
1871        public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1872                int incomingUserId) {
1873            checkCallerIsSystemOrSameApp(pkg);
1874            int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1875                    Binder.getCallingUid(), incomingUserId, true, false,
1876                    "getAppActiveNotifications", pkg);
1877            synchronized (mNotificationLock) {
1878                final ArrayMap<String, StatusBarNotification> map
1879                        = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
1880                final int N = mNotificationList.size();
1881                for (int i = 0; i < N; i++) {
1882                    StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1883                            mNotificationList.get(i).sbn);
1884                    if (sbn != null) {
1885                        map.put(sbn.getKey(), sbn);
1886                    }
1887                }
1888                for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
1889                    StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
1890                    if (sbn != null) {
1891                        map.put(sbn.getKey(), sbn);
1892                    }
1893                }
1894                final int M = mEnqueuedNotifications.size();
1895                for (int i = 0; i < M; i++) {
1896                    StatusBarNotification sbn = sanitizeSbn(pkg, userId,
1897                            mEnqueuedNotifications.get(i).sbn);
1898                    if (sbn != null) {
1899                        map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
1900                    }
1901                }
1902                final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
1903                list.addAll(map.values());
1904                return new ParceledListSlice<StatusBarNotification>(list);
1905            }
1906        }
1907
1908        private StatusBarNotification sanitizeSbn(String pkg, int userId,
1909                StatusBarNotification sbn) {
1910            if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1911                    && (sbn.getNotification().flags
1912                    & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
1913                // We could pass back a cloneLight() but clients might get confused and
1914                // try to send this thing back to notify() again, which would not work
1915                // very well.
1916                return new StatusBarNotification(
1917                        sbn.getPackageName(),
1918                        sbn.getOpPkg(),
1919                        sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1920                        sbn.getNotification().clone(),
1921                        sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
1922            }
1923            return null;
1924        }
1925
1926        /**
1927         * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1928         *
1929         * Requires ACCESS_NOTIFICATIONS which is signature|system.
1930         */
1931        @Override
1932        public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1933            // enforce() will ensure the calling uid has the correct permission
1934            getContext().enforceCallingOrSelfPermission(
1935                    android.Manifest.permission.ACCESS_NOTIFICATIONS,
1936                    "NotificationManagerService.getHistoricalNotifications");
1937
1938            StatusBarNotification[] tmp = null;
1939            int uid = Binder.getCallingUid();
1940
1941            // noteOp will check to make sure the callingPkg matches the uid
1942            if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1943                    == AppOpsManager.MODE_ALLOWED) {
1944                synchronized (mArchive) {
1945                    tmp = mArchive.getArray(count);
1946                }
1947            }
1948            return tmp;
1949        }
1950
1951        /**
1952         * Register a listener binder directly with the notification manager.
1953         *
1954         * Only works with system callers. Apps should extend
1955         * {@link android.service.notification.NotificationListenerService}.
1956         */
1957        @Override
1958        public void registerListener(final INotificationListener listener,
1959                final ComponentName component, final int userid) {
1960            enforceSystemOrSystemUI("INotificationManager.registerListener");
1961            mListeners.registerService(listener, component, userid);
1962        }
1963
1964        /**
1965         * Remove a listener binder directly
1966         */
1967        @Override
1968        public void unregisterListener(INotificationListener token, int userid) {
1969            mListeners.unregisterService(token, userid);
1970        }
1971
1972        /**
1973         * Allow an INotificationListener to simulate a "clear all" operation.
1974         *
1975         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1976         *
1977         * @param token The binder for the listener, to check that the caller is allowed
1978         */
1979        @Override
1980        public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
1981            final int callingUid = Binder.getCallingUid();
1982            final int callingPid = Binder.getCallingPid();
1983            long identity = Binder.clearCallingIdentity();
1984            try {
1985                synchronized (mNotificationLock) {
1986                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1987                    if (keys != null) {
1988                        final int N = keys.length;
1989                        for (int i = 0; i < N; i++) {
1990                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
1991                            if (r == null) continue;
1992                            final int userId = r.sbn.getUserId();
1993                            if (userId != info.userid && userId != UserHandle.USER_ALL &&
1994                                    !mUserProfiles.isCurrentProfile(userId)) {
1995                                throw new SecurityException("Disallowed call from listener: "
1996                                        + info.service);
1997                            }
1998                            cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1999                                    r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2000                                    userId);
2001                        }
2002                    } else {
2003                        cancelAllLocked(callingUid, callingPid, info.userid,
2004                                REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
2005                    }
2006                }
2007            } finally {
2008                Binder.restoreCallingIdentity(identity);
2009            }
2010        }
2011
2012        /**
2013         * Handle request from an approved listener to re-enable itself.
2014         *
2015         * @param component The componenet to be re-enabled, caller must match package.
2016         */
2017        @Override
2018        public void requestBindListener(ComponentName component) {
2019            checkCallerIsSystemOrSameApp(component.getPackageName());
2020            long identity = Binder.clearCallingIdentity();
2021            try {
2022                ManagedServices manager =
2023                        mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
2024                        ? mNotificationAssistants
2025                        : mListeners;
2026                manager.setComponentState(component, true);
2027            } finally {
2028                Binder.restoreCallingIdentity(identity);
2029            }
2030        }
2031
2032        @Override
2033        public void requestUnbindListener(INotificationListener token) {
2034            long identity = Binder.clearCallingIdentity();
2035            try {
2036                // allow bound services to disable themselves
2037                synchronized (mNotificationLock) {
2038                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2039                    info.getOwner().setComponentState(info.component, false);
2040                }
2041            } finally {
2042                Binder.restoreCallingIdentity(identity);
2043            }
2044        }
2045
2046        @Override
2047        public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
2048            long identity = Binder.clearCallingIdentity();
2049            try {
2050                synchronized (mNotificationLock) {
2051                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2052                    if (keys != null) {
2053                        final int N = keys.length;
2054                        for (int i = 0; i < N; i++) {
2055                            NotificationRecord r = mNotificationsByKey.get(keys[i]);
2056                            if (r == null) continue;
2057                            final int userId = r.sbn.getUserId();
2058                            if (userId != info.userid && userId != UserHandle.USER_ALL &&
2059                                    !mUserProfiles.isCurrentProfile(userId)) {
2060                                throw new SecurityException("Disallowed call from listener: "
2061                                        + info.service);
2062                            }
2063                            if (!r.isSeen()) {
2064                                if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2065                                mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2066                                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
2067                                                : userId,
2068                                        UsageEvents.Event.USER_INTERACTION);
2069                                r.setSeen();
2070                            }
2071                        }
2072                    }
2073                }
2074            } finally {
2075                Binder.restoreCallingIdentity(identity);
2076            }
2077        }
2078
2079        /**
2080         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2081         *
2082         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2083         *
2084         * @param info The binder for the listener, to check that the caller is allowed
2085         */
2086        private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
2087                int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
2088            cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2089                    Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2090                    true,
2091                    userId, REASON_LISTENER_CANCEL, info);
2092        }
2093
2094        /**
2095         * Allow an INotificationListener to snooze a single notification until a context.
2096         *
2097         * @param token The binder for the listener, to check that the caller is allowed
2098         */
2099        @Override
2100        public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2101                String key, String snoozeCriterionId) {
2102            long identity = Binder.clearCallingIdentity();
2103            try {
2104                synchronized (mNotificationLock) {
2105                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2106                    snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2107                }
2108            } finally {
2109                Binder.restoreCallingIdentity(identity);
2110            }
2111        }
2112
2113        /**
2114         * Allow an INotificationListener to snooze a single notification until a time.
2115         *
2116         * @param token The binder for the listener, to check that the caller is allowed
2117         */
2118        @Override
2119        public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
2120                long duration) {
2121            long identity = Binder.clearCallingIdentity();
2122            try {
2123                synchronized (mNotificationLock) {
2124                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2125                    snoozeNotificationInt(key, duration, null, info);
2126                }
2127            } finally {
2128                Binder.restoreCallingIdentity(identity);
2129            }
2130        }
2131
2132        /**
2133         * Allows the notification assistant to un-snooze a single notification.
2134         *
2135         * @param token The binder for the assistant, to check that the caller is allowed
2136         */
2137        @Override
2138        public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
2139            long identity = Binder.clearCallingIdentity();
2140            try {
2141                synchronized (mNotificationLock) {
2142                    final ManagedServiceInfo info =
2143                            mNotificationAssistants.checkServiceTokenLocked(token);
2144                    unsnoozeNotificationInt(key, info);
2145                }
2146            } finally {
2147                Binder.restoreCallingIdentity(identity);
2148            }
2149        }
2150
2151        /**
2152         * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2153         *
2154         * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2155         *
2156         * @param token The binder for the listener, to check that the caller is allowed
2157         */
2158        @Override
2159        public void cancelNotificationFromListener(INotificationListener token, String pkg,
2160                String tag, int id) {
2161            final int callingUid = Binder.getCallingUid();
2162            final int callingPid = Binder.getCallingPid();
2163            long identity = Binder.clearCallingIdentity();
2164            try {
2165                synchronized (mNotificationLock) {
2166                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2167                    if (info.supportsProfiles()) {
2168                        Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2169                                + "from " + info.component
2170                                + " use cancelNotification(key) instead.");
2171                    } else {
2172                        cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2173                                pkg, tag, id, info.userid);
2174                    }
2175                }
2176            } finally {
2177                Binder.restoreCallingIdentity(identity);
2178            }
2179        }
2180
2181        /**
2182         * Allow an INotificationListener to request the list of outstanding notifications seen by
2183         * the current user. Useful when starting up, after which point the listener callbacks
2184         * should be used.
2185         *
2186         * @param token The binder for the listener, to check that the caller is allowed
2187         * @param keys An array of notification keys to fetch, or null to fetch everything
2188         * @returns The return value will contain the notifications specified in keys, in that
2189         *      order, or if keys is null, all the notifications, in natural order.
2190         */
2191        @Override
2192        public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
2193                INotificationListener token, String[] keys, int trim) {
2194            synchronized (mNotificationLock) {
2195                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2196                final boolean getKeys = keys != null;
2197                final int N = getKeys ? keys.length : mNotificationList.size();
2198                final ArrayList<StatusBarNotification> list
2199                        = new ArrayList<StatusBarNotification>(N);
2200                for (int i=0; i<N; i++) {
2201                    final NotificationRecord r = getKeys
2202                            ? mNotificationsByKey.get(keys[i])
2203                            : mNotificationList.get(i);
2204                    if (r == null) continue;
2205                    StatusBarNotification sbn = r.sbn;
2206                    if (!isVisibleToListener(sbn, info)) continue;
2207                    StatusBarNotification sbnToSend =
2208                            (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2209                    list.add(sbnToSend);
2210                }
2211                return new ParceledListSlice<StatusBarNotification>(list);
2212            }
2213        }
2214
2215        /**
2216         * Allow an INotificationListener to request the list of outstanding snoozed notifications
2217         * seen by the current user. Useful when starting up, after which point the listener
2218         * callbacks should be used.
2219         *
2220         * @param token The binder for the listener, to check that the caller is allowed
2221         * @returns The return value will contain the notifications specified in keys, in that
2222         *      order, or if keys is null, all the notifications, in natural order.
2223         */
2224        @Override
2225        public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2226                INotificationListener token, int trim) {
2227            synchronized (mNotificationLock) {
2228                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2229                List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2230                final int N = snoozedRecords.size();
2231                final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2232                for (int i=0; i < N; i++) {
2233                    final NotificationRecord r = snoozedRecords.get(i);
2234                    if (r == null) continue;
2235                    StatusBarNotification sbn = r.sbn;
2236                    if (!isVisibleToListener(sbn, info)) continue;
2237                    StatusBarNotification sbnToSend =
2238                            (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2239                    list.add(sbnToSend);
2240                }
2241                return new ParceledListSlice<>(list);
2242            }
2243        }
2244
2245        @Override
2246        public void requestHintsFromListener(INotificationListener token, int hints) {
2247            final long identity = Binder.clearCallingIdentity();
2248            try {
2249                synchronized (mNotificationLock) {
2250                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2251                    final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2252                            | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2253                            | HINT_HOST_DISABLE_CALL_EFFECTS;
2254                    final boolean disableEffects = (hints & disableEffectsMask) != 0;
2255                    if (disableEffects) {
2256                        addDisabledHints(info, hints);
2257                    } else {
2258                        removeDisabledHints(info, hints);
2259                    }
2260                    updateListenerHintsLocked();
2261                    updateEffectsSuppressorLocked();
2262                }
2263            } finally {
2264                Binder.restoreCallingIdentity(identity);
2265            }
2266        }
2267
2268        @Override
2269        public int getHintsFromListener(INotificationListener token) {
2270            synchronized (mNotificationLock) {
2271                return mListenerHints;
2272            }
2273        }
2274
2275        @Override
2276        public void requestInterruptionFilterFromListener(INotificationListener token,
2277                int interruptionFilter) throws RemoteException {
2278            final long identity = Binder.clearCallingIdentity();
2279            try {
2280                synchronized (mNotificationLock) {
2281                    final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2282                    mZenModeHelper.requestFromListener(info.component, interruptionFilter);
2283                    updateInterruptionFilterLocked();
2284                }
2285            } finally {
2286                Binder.restoreCallingIdentity(identity);
2287            }
2288        }
2289
2290        @Override
2291        public int getInterruptionFilterFromListener(INotificationListener token)
2292                throws RemoteException {
2293            synchronized (mNotificationLight) {
2294                return mInterruptionFilter;
2295            }
2296        }
2297
2298        @Override
2299        public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2300                throws RemoteException {
2301            synchronized (mNotificationLock) {
2302                final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2303                if (info == null) return;
2304                mListeners.setOnNotificationPostedTrimLocked(info, trim);
2305            }
2306        }
2307
2308        @Override
2309        public int getZenMode() {
2310            return mZenModeHelper.getZenMode();
2311        }
2312
2313        @Override
2314        public ZenModeConfig getZenModeConfig() {
2315            enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
2316            return mZenModeHelper.getConfig();
2317        }
2318
2319        @Override
2320        public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
2321            enforceSystemOrSystemUI("INotificationManager.setZenMode");
2322            final long identity = Binder.clearCallingIdentity();
2323            try {
2324                mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
2325            } finally {
2326                Binder.restoreCallingIdentity(identity);
2327            }
2328        }
2329
2330        @Override
2331        public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
2332            enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
2333            return mZenModeHelper.getZenRules();
2334        }
2335
2336        @Override
2337        public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2338            Preconditions.checkNotNull(id, "Id is null");
2339            enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
2340            return mZenModeHelper.getAutomaticZenRule(id);
2341        }
2342
2343        @Override
2344        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
2345                throws RemoteException {
2346            Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2347            Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2348            Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2349            Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2350            enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
2351
2352            return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2353                    "addAutomaticZenRule");
2354        }
2355
2356        @Override
2357        public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
2358                throws RemoteException {
2359            Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2360            Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2361            Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2362            Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2363            enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
2364
2365            return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
2366                    "updateAutomaticZenRule");
2367        }
2368
2369        @Override
2370        public boolean removeAutomaticZenRule(String id) throws RemoteException {
2371            Preconditions.checkNotNull(id, "Id is null");
2372            // Verify that they can modify zen rules.
2373            enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2374
2375            return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
2376        }
2377
2378        @Override
2379        public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2380            Preconditions.checkNotNull(packageName, "Package name is null");
2381            enforceSystemOrSystemUI("removeAutomaticZenRules");
2382
2383            return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2384        }
2385
2386        @Override
2387        public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2388            Preconditions.checkNotNull(owner, "Owner is null");
2389            enforceSystemOrSystemUI("getRuleInstanceCount");
2390
2391            return mZenModeHelper.getCurrentInstanceCount(owner);
2392        }
2393
2394        @Override
2395        public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2396            enforcePolicyAccess(pkg, "setInterruptionFilter");
2397            final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2398            if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2399            final long identity = Binder.clearCallingIdentity();
2400            try {
2401                mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
2402            } finally {
2403                Binder.restoreCallingIdentity(identity);
2404            }
2405        }
2406
2407        @Override
2408        public void notifyConditions(final String pkg, IConditionProvider provider,
2409                final Condition[] conditions) {
2410            final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2411            checkCallerIsSystemOrSameApp(pkg);
2412            mHandler.post(new Runnable() {
2413                @Override
2414                public void run() {
2415                    mConditionProviders.notifyConditions(pkg, info, conditions);
2416                }
2417            });
2418        }
2419
2420        @Override
2421        public void requestUnbindProvider(IConditionProvider provider) {
2422            long identity = Binder.clearCallingIdentity();
2423            try {
2424                // allow bound services to disable themselves
2425                final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2426                info.getOwner().setComponentState(info.component, false);
2427            } finally {
2428                Binder.restoreCallingIdentity(identity);
2429            }
2430        }
2431
2432        @Override
2433        public void requestBindProvider(ComponentName component) {
2434            checkCallerIsSystemOrSameApp(component.getPackageName());
2435            long identity = Binder.clearCallingIdentity();
2436            try {
2437                mConditionProviders.setComponentState(component, true);
2438            } finally {
2439                Binder.restoreCallingIdentity(identity);
2440            }
2441        }
2442
2443        private void enforceSystemOrSystemUI(String message) {
2444            if (isCallerSystem()) return;
2445            getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2446                    message);
2447        }
2448
2449        private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2450            try {
2451                checkCallerIsSystemOrSameApp(pkg);
2452            } catch (SecurityException e) {
2453                getContext().enforceCallingPermission(
2454                        android.Manifest.permission.STATUS_BAR_SERVICE,
2455                        message);
2456            }
2457        }
2458
2459        private void enforcePolicyAccess(int uid, String method) {
2460            if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2461                    android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2462                return;
2463            }
2464            boolean accessAllowed = false;
2465            String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2466            final int packageCount = packages.length;
2467            for (int i = 0; i < packageCount; i++) {
2468                if (checkPolicyAccess(packages[i])) {
2469                    accessAllowed = true;
2470                }
2471            }
2472            if (!accessAllowed) {
2473                Slog.w(TAG, "Notification policy access denied calling " + method);
2474                throw new SecurityException("Notification policy access denied");
2475            }
2476        }
2477
2478        private void enforcePolicyAccess(String pkg, String method) {
2479            if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2480                    android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2481                return;
2482            }
2483            checkCallerIsSameApp(pkg);
2484            if (!checkPolicyAccess(pkg)) {
2485                Slog.w(TAG, "Notification policy access denied calling " + method);
2486                throw new SecurityException("Notification policy access denied");
2487            }
2488        }
2489
2490        private boolean checkPackagePolicyAccess(String pkg) {
2491            return mPolicyAccess.isPackageGranted(pkg);
2492        }
2493
2494        private boolean checkPolicyAccess(String pkg) {
2495            try {
2496                int uid = getContext().getPackageManager().getPackageUidAsUser(
2497                        pkg, UserHandle.getCallingUserId());
2498                if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2499                        android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2500                        -1, true)) {
2501                    return true;
2502                }
2503            } catch (NameNotFoundException e) {
2504                return false;
2505            }
2506            return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
2507        }
2508
2509        @Override
2510        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2511            if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
2512            final DumpFilter filter = DumpFilter.parseFromArguments(args);
2513            if (filter != null && filter.stats) {
2514                dumpJson(pw, filter);
2515            } else if (filter != null && filter.proto) {
2516                dumpProto(fd, filter);
2517            } else {
2518                dumpImpl(pw, filter);
2519            }
2520        }
2521
2522        @Override
2523        public ComponentName getEffectsSuppressor() {
2524            return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
2525        }
2526
2527        @Override
2528        public boolean matchesCallFilter(Bundle extras) {
2529            enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
2530            return mZenModeHelper.matchesCallFilter(
2531                    Binder.getCallingUserHandle(),
2532                    extras,
2533                    mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2534                    MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2535                    MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
2536        }
2537
2538        @Override
2539        public boolean isSystemConditionProviderEnabled(String path) {
2540            enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
2541            return mConditionProviders.isSystemProviderEnabled(path);
2542        }
2543
2544        // Backup/restore interface
2545        @Override
2546        public byte[] getBackupPayload(int user) {
2547            if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
2548            //TODO: http://b/22388012
2549            if (user != UserHandle.USER_SYSTEM) {
2550                Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2551                return null;
2552            }
2553            synchronized(mPolicyFile) {
2554                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2555                try {
2556                    writePolicyXml(baos, true /*forBackup*/);
2557                    return baos.toByteArray();
2558                } catch (IOException e) {
2559                    Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2560                }
2561            }
2562            return null;
2563        }
2564
2565        @Override
2566        public void applyRestore(byte[] payload, int user) {
2567            if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2568                    + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2569            if (payload == null) {
2570                Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2571                return;
2572            }
2573            //TODO: http://b/22388012
2574            if (user != UserHandle.USER_SYSTEM) {
2575                Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2576                return;
2577            }
2578            synchronized(mPolicyFile) {
2579                final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2580                try {
2581                    readPolicyXml(bais, true /*forRestore*/);
2582                    savePolicyFile();
2583                } catch (NumberFormatException | XmlPullParserException | IOException e) {
2584                    Slog.w(TAG, "applyRestore: error reading payload", e);
2585                }
2586            }
2587        }
2588
2589        @Override
2590        public boolean isNotificationPolicyAccessGranted(String pkg) {
2591            return checkPolicyAccess(pkg);
2592        }
2593
2594        @Override
2595        public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2596            enforceSystemOrSystemUIOrSamePackage(pkg,
2597                    "request policy access status for another package");
2598            return checkPolicyAccess(pkg);
2599        }
2600
2601        @Override
2602        public String[] getPackagesRequestingNotificationPolicyAccess()
2603                throws RemoteException {
2604            enforceSystemOrSystemUI("request policy access packages");
2605            final long identity = Binder.clearCallingIdentity();
2606            try {
2607                return mPolicyAccess.getRequestingPackages();
2608            } finally {
2609                Binder.restoreCallingIdentity(identity);
2610            }
2611        }
2612
2613        @Override
2614        public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2615                throws RemoteException {
2616            enforceSystemOrSystemUI("grant notification policy access");
2617            final long identity = Binder.clearCallingIdentity();
2618            try {
2619                synchronized (mNotificationLock) {
2620                    mPolicyAccess.put(pkg, granted);
2621                }
2622            } finally {
2623                Binder.restoreCallingIdentity(identity);
2624            }
2625        }
2626
2627        @Override
2628        public Policy getNotificationPolicy(String pkg) {
2629            enforcePolicyAccess(pkg, "getNotificationPolicy");
2630            final long identity = Binder.clearCallingIdentity();
2631            try {
2632                return mZenModeHelper.getNotificationPolicy();
2633            } finally {
2634                Binder.restoreCallingIdentity(identity);
2635            }
2636        }
2637
2638        @Override
2639        public void setNotificationPolicy(String pkg, Policy policy) {
2640            enforcePolicyAccess(pkg, "setNotificationPolicy");
2641            final long identity = Binder.clearCallingIdentity();
2642            try {
2643                mZenModeHelper.setNotificationPolicy(policy);
2644            } finally {
2645                Binder.restoreCallingIdentity(identity);
2646            }
2647        }
2648
2649        @Override
2650        public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2651                Adjustment adjustment) throws RemoteException {
2652            final long identity = Binder.clearCallingIdentity();
2653            try {
2654                synchronized (mNotificationLock) {
2655                    mNotificationAssistants.checkServiceTokenLocked(token);
2656                    int N = mEnqueuedNotifications.size();
2657                    for (int i = 0; i < N; i++) {
2658                        final NotificationRecord n = mEnqueuedNotifications.get(i);
2659                        if (Objects.equals(adjustment.getKey(), n.getKey())
2660                                && Objects.equals(adjustment.getUser(), n.getUserId())) {
2661                            applyAdjustment(n, adjustment);
2662                            break;
2663                        }
2664                    }
2665                }
2666            } finally {
2667                Binder.restoreCallingIdentity(identity);
2668            }
2669        }
2670
2671        @Override
2672        public void applyAdjustmentFromAssistant(INotificationListener token,
2673                Adjustment adjustment) throws RemoteException {
2674            final long identity = Binder.clearCallingIdentity();
2675            try {
2676                synchronized (mNotificationLock) {
2677                    mNotificationAssistants.checkServiceTokenLocked(token);
2678                    NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2679                    applyAdjustment(n, adjustment);
2680                }
2681                mRankingHandler.requestSort(true);
2682            } finally {
2683                Binder.restoreCallingIdentity(identity);
2684            }
2685        }
2686
2687        @Override
2688        public void applyAdjustmentsFromAssistant(INotificationListener token,
2689                List<Adjustment> adjustments) throws RemoteException {
2690
2691            final long identity = Binder.clearCallingIdentity();
2692            try {
2693                synchronized (mNotificationLock) {
2694                    mNotificationAssistants.checkServiceTokenLocked(token);
2695                    for (Adjustment adjustment : adjustments) {
2696                        NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2697                        applyAdjustment(n, adjustment);
2698                    }
2699                }
2700                mRankingHandler.requestSort(true);
2701            } finally {
2702                Binder.restoreCallingIdentity(identity);
2703            }
2704        }
2705
2706        @Override
2707        public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
2708                String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
2709            Preconditions.checkNotNull(channel);
2710            Preconditions.checkNotNull(pkg);
2711            Preconditions.checkNotNull(user);
2712
2713            verifyPrivilegedListener(token, user);
2714            updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
2715        }
2716
2717        @Override
2718        public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
2719                INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2720            Preconditions.checkNotNull(pkg);
2721            Preconditions.checkNotNull(user);
2722            verifyPrivilegedListener(token, user);
2723
2724            return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2725                    false /* includeDeleted */);
2726        }
2727
2728        @Override
2729        public ParceledListSlice<NotificationChannelGroup>
2730                getNotificationChannelGroupsFromPrivilegedListener(
2731                INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2732            Preconditions.checkNotNull(pkg);
2733            Preconditions.checkNotNull(user);
2734            verifyPrivilegedListener(token, user);
2735
2736            List<NotificationChannelGroup> groups = new ArrayList<>();
2737            groups.addAll(mRankingHelper.getNotificationChannelGroups(
2738                    pkg, getUidForPackageAndUser(pkg, user)));
2739            return new ParceledListSlice<>(groups);
2740        }
2741
2742        private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
2743            ManagedServiceInfo info;
2744            synchronized (mNotificationLock) {
2745                info = mListeners.checkServiceTokenLocked(token);
2746            }
2747            if (!hasCompanionDevice(info)) {
2748                throw new SecurityException(info + " does not have access");
2749            }
2750            if (!info.enabledAndUserMatches(user.getIdentifier())) {
2751                throw new SecurityException(info + " does not have access");
2752            }
2753        }
2754
2755        private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
2756            int uid = 0;
2757            long identity = Binder.clearCallingIdentity();
2758            try {
2759                uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
2760            } finally {
2761                Binder.restoreCallingIdentity(identity);
2762            }
2763            return uid;
2764        }
2765    };
2766
2767    private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
2768        if (n == null) {
2769            return;
2770        }
2771        if (adjustment.getSignals() != null) {
2772            Bundle.setDefusable(adjustment.getSignals(), true);
2773            final ArrayList<String> people =
2774                    adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
2775            final ArrayList<SnoozeCriterion> snoozeCriterionList =
2776                    adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
2777            n.setPeopleOverride(people);
2778            n.setSnoozeCriteria(snoozeCriterionList);
2779        }
2780    }
2781
2782    private void addAutogroupKeyLocked(String key) {
2783        NotificationRecord n = mNotificationsByKey.get(key);
2784        if (n == null) {
2785            return;
2786        }
2787        n.sbn.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
2788        EventLogTags.writeNotificationAutogrouped(key);
2789    }
2790
2791    private void removeAutogroupKeyLocked(String key) {
2792        NotificationRecord n = mNotificationsByKey.get(key);
2793        if (n == null) {
2794            return;
2795        }
2796        n.sbn.setOverrideGroupKey(null);
2797        EventLogTags.writeNotificationUnautogrouped(key);
2798    }
2799
2800    // Clears the 'fake' auto-group summary.
2801    private void clearAutogroupSummaryLocked(int userId, String pkg) {
2802        ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2803        if (summaries != null && summaries.containsKey(pkg)) {
2804            // Clear summary.
2805            final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
2806            if (removed != null) {
2807                cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2808            }
2809        }
2810    }
2811
2812    // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2813    private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
2814        NotificationRecord summaryRecord = null;
2815        synchronized (mNotificationLock) {
2816            NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
2817            if (notificationRecord == null) {
2818                // The notification could have been cancelled again already. A successive
2819                // adjustment will post a summary if needed.
2820                return;
2821            }
2822            final StatusBarNotification adjustedSbn = notificationRecord.sbn;
2823            userId = adjustedSbn.getUser().getIdentifier();
2824            ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2825            if (summaries == null) {
2826                summaries = new ArrayMap<>();
2827            }
2828            mAutobundledSummaries.put(userId, summaries);
2829            if (!summaries.containsKey(pkg)) {
2830                // Add summary
2831                final ApplicationInfo appInfo =
2832                       adjustedSbn.getNotification().extras.getParcelable(
2833                               Notification.EXTRA_BUILDER_APPLICATION_INFO);
2834                final Bundle extras = new Bundle();
2835                extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2836                final String channelId = notificationRecord.getChannel().getId();
2837                final Notification summaryNotification =
2838                        new Notification.Builder(getContext(), channelId)
2839                                .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
2840                                .setGroupSummary(true)
2841                                .setGroup(GroupHelper.AUTOGROUP_KEY)
2842                                .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2843                                .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
2844                                .setColor(adjustedSbn.getNotification().color)
2845                                .setLocalOnly(true)
2846                                .build();
2847                summaryNotification.extras.putAll(extras);
2848                Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
2849                if (appIntent != null) {
2850                    summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2851                            getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
2852                }
2853                final StatusBarNotification summarySbn =
2854                        new StatusBarNotification(adjustedSbn.getPackageName(),
2855                                adjustedSbn.getOpPkg(),
2856                                Integer.MAX_VALUE,
2857                                GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
2858                                adjustedSbn.getInitialPid(), summaryNotification,
2859                                adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
2860                                System.currentTimeMillis());
2861                summaryRecord = new NotificationRecord(getContext(), summarySbn,
2862                        notificationRecord.getChannel());
2863                summaries.put(pkg, summarySbn.getKey());
2864            }
2865        }
2866        if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
2867                summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
2868            mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2869        }
2870    }
2871
2872    private String disableNotificationEffects(NotificationRecord record) {
2873        if (mDisableNotificationEffects) {
2874            return "booleanState";
2875        }
2876        if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2877            return "listenerHints";
2878        }
2879        if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2880            return "callState";
2881        }
2882        return null;
2883    };
2884
2885    private void dumpJson(PrintWriter pw, DumpFilter filter) {
2886        JSONObject dump = new JSONObject();
2887        try {
2888            dump.put("service", "Notification Manager");
2889            dump.put("bans", mRankingHelper.dumpBansJson(filter));
2890            dump.put("ranking", mRankingHelper.dumpJson(filter));
2891            dump.put("stats", mUsageStats.dumpJson(filter));
2892            dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
2893        } catch (JSONException e) {
2894            e.printStackTrace();
2895        }
2896        pw.println(dump);
2897    }
2898
2899    private void dumpProto(FileDescriptor fd, DumpFilter filter) {
2900        final ProtoOutputStream proto = new ProtoOutputStream(fd);
2901        synchronized (mNotificationLock) {
2902            long records = proto.start(NotificationServiceDumpProto.RECORDS);
2903            int N = mNotificationList.size();
2904            if (N > 0) {
2905                for (int i = 0; i < N; i++) {
2906                    final NotificationRecord nr = mNotificationList.get(i);
2907                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
2908                    nr.dump(proto, filter.redact);
2909                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
2910                }
2911            }
2912            N = mEnqueuedNotifications.size();
2913            if (N > 0) {
2914                for (int i = 0; i < N; i++) {
2915                    final NotificationRecord nr = mEnqueuedNotifications.get(i);
2916                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
2917                    nr.dump(proto, filter.redact);
2918                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
2919                }
2920            }
2921            List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
2922            N = snoozed.size();
2923            if (N > 0) {
2924                for (int i = 0; i < N; i++) {
2925                    final NotificationRecord nr = snoozed.get(i);
2926                    if (filter.filtered && !filter.matches(nr.sbn)) continue;
2927                    nr.dump(proto, filter.redact);
2928                    proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
2929                }
2930            }
2931            proto.end(records);
2932        }
2933
2934        long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
2935        mZenModeHelper.dump(proto);
2936        for (ComponentName suppressor : mEffectsSuppressors) {
2937            proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
2938        }
2939        proto.end(zenLog);
2940
2941        proto.flush();
2942    }
2943
2944    void dumpImpl(PrintWriter pw, DumpFilter filter) {
2945        pw.print("Current Notification Manager state");
2946        if (filter.filtered) {
2947            pw.print(" (filtered to "); pw.print(filter); pw.print(")");
2948        }
2949        pw.println(':');
2950        int N;
2951        final boolean zenOnly = filter.filtered && filter.zen;
2952
2953        if (!zenOnly) {
2954            synchronized (mToastQueue) {
2955                N = mToastQueue.size();
2956                if (N > 0) {
2957                    pw.println("  Toast Queue:");
2958                    for (int i=0; i<N; i++) {
2959                        mToastQueue.get(i).dump(pw, "    ", filter);
2960                    }
2961                    pw.println("  ");
2962                }
2963            }
2964        }
2965
2966        synchronized (mNotificationLock) {
2967            if (!zenOnly) {
2968                N = mNotificationList.size();
2969                if (N > 0) {
2970                    pw.println("  Notification List:");
2971                    for (int i=0; i<N; i++) {
2972                        final NotificationRecord nr = mNotificationList.get(i);
2973                        if (filter.filtered && !filter.matches(nr.sbn)) continue;
2974                        nr.dump(pw, "    ", getContext(), filter.redact);
2975                    }
2976                    pw.println("  ");
2977                }
2978
2979                if (!filter.filtered) {
2980                    N = mLights.size();
2981                    if (N > 0) {
2982                        pw.println("  Lights List:");
2983                        for (int i=0; i<N; i++) {
2984                            if (i == N - 1) {
2985                                pw.print("  > ");
2986                            } else {
2987                                pw.print("    ");
2988                            }
2989                            pw.println(mLights.get(i));
2990                        }
2991                        pw.println("  ");
2992                    }
2993                    pw.println("  mUseAttentionLight=" + mUseAttentionLight);
2994                    pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
2995                    pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
2996                    pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
2997                    pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
2998                    pw.println("  mCallState=" + callStateToString(mCallState));
2999                    pw.println("  mSystemReady=" + mSystemReady);
3000                    pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
3001                }
3002                pw.println("  mArchive=" + mArchive.toString());
3003                Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
3004                int j=0;
3005                while (iter.hasNext()) {
3006                    final StatusBarNotification sbn = iter.next();
3007                    if (filter != null && !filter.matches(sbn)) continue;
3008                    pw.println("    " + sbn);
3009                    if (++j >= 5) {
3010                        if (iter.hasNext()) pw.println("    ...");
3011                        break;
3012                    }
3013                }
3014
3015                if (!zenOnly) {
3016                    N = mEnqueuedNotifications.size();
3017                    if (N > 0) {
3018                        pw.println("  Enqueued Notification List:");
3019                        for (int i = 0; i < N; i++) {
3020                            final NotificationRecord nr = mEnqueuedNotifications.get(i);
3021                            if (filter.filtered && !filter.matches(nr.sbn)) continue;
3022                            nr.dump(pw, "    ", getContext(), filter.redact);
3023                        }
3024                        pw.println("  ");
3025                    }
3026
3027                    mSnoozeHelper.dump(pw, filter);
3028                }
3029            }
3030
3031            if (!zenOnly) {
3032                pw.println("\n  Ranking Config:");
3033                mRankingHelper.dump(pw, "    ", filter);
3034
3035                pw.println("\n  Notification listeners:");
3036                mListeners.dump(pw, filter);
3037                pw.print("    mListenerHints: "); pw.println(mListenerHints);
3038                pw.print("    mListenersDisablingEffects: (");
3039                N = mListenersDisablingEffects.size();
3040                for (int i = 0; i < N; i++) {
3041                    final int hint = mListenersDisablingEffects.keyAt(i);
3042                    if (i > 0) pw.print(';');
3043                    pw.print("hint[" + hint + "]:");
3044
3045                    final ArraySet<ManagedServiceInfo> listeners =
3046                            mListenersDisablingEffects.valueAt(i);
3047                    final int listenerSize = listeners.size();
3048
3049                    for (int j = 0; j < listenerSize; j++) {
3050                        if (i > 0) pw.print(',');
3051                        final ManagedServiceInfo listener = listeners.valueAt(i);
3052                        pw.print(listener.component);
3053                    }
3054                }
3055                pw.println(')');
3056                pw.println("\n  Notification assistant services:");
3057                mNotificationAssistants.dump(pw, filter);
3058            }
3059
3060            if (!filter.filtered || zenOnly) {
3061                pw.println("\n  Zen Mode:");
3062                pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
3063                mZenModeHelper.dump(pw, "    ");
3064
3065                pw.println("\n  Zen Log:");
3066                ZenLog.dump(pw, "    ");
3067            }
3068
3069            pw.println("\n  Policy access:");
3070            pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
3071
3072            pw.println("\n  Condition providers:");
3073            mConditionProviders.dump(pw, filter);
3074
3075            pw.println("\n  Group summaries:");
3076            for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3077                NotificationRecord r = entry.getValue();
3078                pw.println("    " + entry.getKey() + " -> " + r.getKey());
3079                if (mNotificationsByKey.get(r.getKey()) != r) {
3080                    pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
3081                    r.dump(pw, "      ", getContext(), filter.redact);
3082                }
3083            }
3084
3085            if (!zenOnly) {
3086                pw.println("\n  Usage Stats:");
3087                mUsageStats.dump(pw, "    ", filter);
3088            }
3089        }
3090    }
3091
3092    /**
3093     * The private API only accessible to the system process.
3094     */
3095    private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3096        @Override
3097        public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
3098                String tag, int id, Notification notification, int[] idReceived, int userId) {
3099            enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
3100                    idReceived, userId);
3101        }
3102
3103        @Override
3104        public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3105                int userId) {
3106            checkCallerIsSystem();
3107            mHandler.post(new Runnable() {
3108                @Override
3109                public void run() {
3110                    synchronized (mNotificationLock) {
3111                        removeForegroundServiceFlagByListLocked(
3112                                mEnqueuedNotifications, pkg, notificationId, userId);
3113                        removeForegroundServiceFlagByListLocked(
3114                                mNotificationList, pkg, notificationId, userId);
3115                    }
3116                }
3117            });
3118        }
3119
3120        private void removeForegroundServiceFlagByListLocked(
3121                ArrayList<NotificationRecord> notificationList, String pkg, int notificationId, int userId) {
3122            NotificationRecord r =
3123                    findNotificationByListLocked(notificationList, pkg, null, notificationId, userId);
3124            if (r == null) {
3125                return;
3126            }
3127            StatusBarNotification sbn = r.sbn;
3128            // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3129            // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3130            // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3131            // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3132            sbn.getNotification().flags =
3133                    (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3134            mRankingHelper.sort(mNotificationList);
3135            mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
3136            mGroupHelper.onNotificationPosted(sbn);
3137        }
3138    };
3139
3140    void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
3141            final int callingPid, final String tag, final int id, final Notification notification,
3142            int[] idOut, int incomingUserId) {
3143        if (DBG) {
3144            Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3145                    + " notification=" + notification);
3146        }
3147        checkCallerIsSystemOrSameApp(pkg);
3148
3149        final int userId = ActivityManager.handleIncomingUser(callingPid,
3150                callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
3151        final UserHandle user = new UserHandle(userId);
3152
3153        if (pkg == null || notification == null) {
3154            throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3155                    + " id=" + id + " notification=" + notification);
3156        }
3157
3158        // The system can post notifications for any package, let us resolve that.
3159        final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3160
3161        // Fix the notification as best we can.
3162        try {
3163            final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
3164                    pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3165                    (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
3166            Notification.addFieldsFromContext(ai, notification);
3167        } catch (NameNotFoundException e) {
3168            Slog.e(TAG, "Cannot create a context for sending app", e);
3169            return;
3170        }
3171
3172        mUsageStats.registerEnqueuedByApp(pkg);
3173
3174        // setup local book-keeping
3175        String channelId = notification.getChannel();
3176        if (mIsTelevision && (new Notification.TvExtender(notification)).getChannel() != null) {
3177            channelId = (new Notification.TvExtender(notification)).getChannel();
3178        }
3179        final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
3180                notificationUid, channelId, false /* includeDeleted */);
3181        if (channel == null) {
3182            // STOPSHIP TODO: remove before release - should always throw without a valid channel.
3183            if (channelId == null) {
3184                Log.e(TAG, "Cannot post notification without channel ID when targeting O "
3185                        + " - notification=" + notification);
3186                return;
3187            }
3188            final String noChannelStr = "No Channel found for "
3189                    + "pkg=" + pkg
3190                    + ", channelId=" + channelId
3191                    + ", opPkg=" + opPkg
3192                    + ", callingUid=" + callingUid
3193                    + ", userId=" + userId
3194                    + ", incomingUserId=" + incomingUserId
3195                    + ", notificationUid=" + notificationUid
3196                    + ", notification=" + notification;
3197            // STOPSHIP TODO: should throw instead of logging or toasting.
3198            // throw new IllegalArgumentException(noChannelStr);
3199            Log.e(TAG, noChannelStr);
3200            doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" +
3201                    "Failed to post notification on channel \"" + channelId + "\"\n" +
3202                    "See log for more details");
3203            return;
3204        } else if (channelId == null && shouldWarnUseChannels(pkg, notificationUid)) {
3205            // STOPSHIP TODO: remove once default channel is removed for all apps that target O.
3206            Log.e(TAG, "Developer Warning for package " + pkg
3207                    + ", no channel specified for posted notification: " + notification);
3208            doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" +
3209                    "Posted notification should specify a channel");
3210        }
3211
3212        final StatusBarNotification n = new StatusBarNotification(
3213                pkg, opPkg, id, tag, notificationUid, callingPid, notification,
3214                user, null, System.currentTimeMillis());
3215        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
3216
3217        if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
3218            return;
3219        }
3220
3221        // Whitelist pending intents.
3222        if (notification.allPendingIntents != null) {
3223            final int intentCount = notification.allPendingIntents.size();
3224            if (intentCount > 0) {
3225                final ActivityManagerInternal am = LocalServices
3226                        .getService(ActivityManagerInternal.class);
3227                final long duration = LocalServices.getService(
3228                        DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3229                for (int i = 0; i < intentCount; i++) {
3230                    PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3231                    if (pendingIntent != null) {
3232                        am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
3233                    }
3234                }
3235            }
3236        }
3237
3238        mHandler.post(new EnqueueNotificationRunnable(userId, r));
3239
3240        idOut[0] = id;
3241    }
3242
3243    private void doDebugOnlyToast(CharSequence toastText) {
3244        if (Build.IS_DEBUGGABLE) {
3245            try {
3246                Toast toast = Toast.makeText(getContext(), toastText, Toast.LENGTH_LONG);
3247                toast.show();
3248            } catch (RuntimeException e) {
3249                Slog.w(TAG, "Unable to toast with text: " + toastText, e);
3250            }
3251        }
3252    }
3253
3254    // STOPSHIP - Remove once RankingHelper deletes default channel for all apps targeting O.
3255    private boolean shouldWarnUseChannels(String pkg, int uid) {
3256        try {
3257            final int userId = UserHandle.getUserId(uid);
3258            final ApplicationInfo applicationInfo =
3259                    mPackageManagerClient.getApplicationInfoAsUser(pkg, 0, userId);
3260            return applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1;
3261        } catch (NameNotFoundException e) {
3262            Slog.e(TAG, e.toString());
3263            return false;
3264        }
3265    }
3266
3267    private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3268        // The system can post notifications on behalf of any package it wants
3269        if (isCallerSystem() && opPackageName != null && !"android".equals(opPackageName)) {
3270            try {
3271                return getContext().getPackageManager()
3272                        .getPackageUidAsUser(opPackageName, userId);
3273            } catch (NameNotFoundException e) {
3274                /* ignore */
3275            }
3276        }
3277        return callingUid;
3278    }
3279
3280    /**
3281     * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3282     *
3283     * Has side effects.
3284     */
3285    private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
3286            NotificationRecord r) {
3287        final String pkg = r.sbn.getPackageName();
3288        final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
3289        final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3290
3291        // Limit the number of notifications that any given package except the android
3292        // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
3293        if (!isSystemNotification && !isNotificationFromListener) {
3294            synchronized (mNotificationLock) {
3295                if (mNotificationsByKey.get(r.sbn.getKey()) != null) {
3296                    // this is an update, rate limit updates only
3297                    final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3298                    if (appEnqueueRate > mMaxPackageEnqueueRate) {
3299                        mUsageStats.registerOverRateQuota(pkg);
3300                        final long now = SystemClock.elapsedRealtime();
3301                        if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3302                            Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
3303                                    + ". Shedding events. package=" + pkg);
3304                            mLastOverRateLogTime = now;
3305                        }
3306                        return false;
3307                    }
3308                } else if (isCallerInstantApp(pkg)) {
3309                    // Ephemeral apps have some special contraints for notifications.
3310                    // They are not allowed to create new notifications however they are allowed to
3311                    // update notifications created by the system (e.g. a foreground service
3312                    // notification).
3313                    throw new SecurityException("Instant app " + pkg
3314                            + " cannot create notifications");
3315                }
3316
3317                int count = 0;
3318                final int N = mNotificationList.size();
3319                for (int i=0; i<N; i++) {
3320                    final NotificationRecord existing = mNotificationList.get(i);
3321                    if (existing.sbn.getPackageName().equals(pkg)
3322                            && existing.sbn.getUserId() == userId) {
3323                        if (existing.sbn.getId() == id
3324                                && TextUtils.equals(existing.sbn.getTag(), tag)) {
3325                            break;  // Allow updating existing notification
3326                        }
3327                        count++;
3328                        if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3329                            mUsageStats.registerOverCountQuota(pkg);
3330                            Slog.e(TAG, "Package has already posted " + count
3331                                    + " notifications.  Not showing more.  package=" + pkg);
3332                            return false;
3333                        }
3334                    }
3335                }
3336            }
3337        }
3338
3339        // snoozed apps
3340        if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
3341            MetricsLogger.action(r.getLogMaker()
3342                    .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3343                    .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
3344            if (DBG) {
3345                Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3346            }
3347            mSnoozeHelper.update(userId, r);
3348            savePolicyFile();
3349            return false;
3350        }
3351
3352
3353        // blocked apps
3354        if (isBlocked(r, mUsageStats)) {
3355            return false;
3356        }
3357
3358        return true;
3359    }
3360
3361    protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3362        final String pkg = r.sbn.getPackageName();
3363        final int callingUid = r.sbn.getUid();
3364
3365        final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3366        if (isPackageSuspended) {
3367            Slog.e(TAG, "Suppressing notification from package due to package "
3368                    + "suspended by administrator.");
3369            usageStats.registerSuspendedByAdmin(r);
3370            return isPackageSuspended;
3371        }
3372
3373        final boolean isBlocked = r.getImportance() == NotificationManager.IMPORTANCE_NONE
3374                || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE
3375                || !noteNotificationOp(pkg, callingUid);
3376        if (isBlocked) {
3377            Slog.e(TAG, "Suppressing notification from package by user request.");
3378            usageStats.registerBlocked(r);
3379        }
3380        return isBlocked;
3381    }
3382
3383    protected class EnqueueNotificationRunnable implements Runnable {
3384        private final NotificationRecord r;
3385        private final int userId;
3386
3387        EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3388            this.userId = userId;
3389            this.r = r;
3390        };
3391
3392        @Override
3393        public void run() {
3394            synchronized (mNotificationLock) {
3395                mEnqueuedNotifications.add(r);
3396                scheduleTimeoutLocked(r);
3397
3398                final StatusBarNotification n = r.sbn;
3399                if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3400                NotificationRecord old = mNotificationsByKey.get(n.getKey());
3401                if (old != null) {
3402                    // Retain ranking information from previous record
3403                    r.copyRankingInformation(old);
3404                }
3405
3406                final int callingUid = n.getUid();
3407                final int callingPid = n.getInitialPid();
3408                final Notification notification = n.getNotification();
3409                final String pkg = n.getPackageName();
3410                final int id = n.getId();
3411                final String tag = n.getTag();
3412
3413                // Handle grouped notifications and bail out early if we
3414                // can to avoid extracting signals.
3415                handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3416
3417                // This conditional is a dirty hack to limit the logging done on
3418                //     behalf of the download manager without affecting other apps.
3419                if (!pkg.equals("com.android.providers.downloads")
3420                        || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3421                    int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
3422                    if (old != null) {
3423                        enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
3424                    }
3425                    EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3426                            pkg, id, tag, userId, notification.toString(),
3427                            enqueueStatus);
3428                }
3429
3430                mRankingHelper.extractSignals(r);
3431
3432                // tell the assistant service about the notification
3433                if (mNotificationAssistants.isEnabled()) {
3434                    mNotificationAssistants.onNotificationEnqueued(r);
3435                    mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
3436                            DELAY_FOR_ASSISTANT_TIME);
3437                } else {
3438                    mHandler.post(new PostNotificationRunnable(r.getKey()));
3439                }
3440            }
3441        }
3442    }
3443
3444    protected class PostNotificationRunnable implements Runnable {
3445        private final String key;
3446
3447        PostNotificationRunnable(String key) {
3448            this.key = key;
3449        }
3450
3451        @Override
3452        public void run() {
3453            synchronized (mNotificationLock) {
3454                try {
3455                    NotificationRecord r = null;
3456                    int N = mEnqueuedNotifications.size();
3457                    for (int i = 0; i < N; i++) {
3458                        final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3459                        if (Objects.equals(key, enqueued.getKey())) {
3460                            r = enqueued;
3461                            break;
3462                        }
3463                    }
3464                    if (r == null) {
3465                        Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3466                        return;
3467                    }
3468                    NotificationRecord old = mNotificationsByKey.get(key);
3469                    final StatusBarNotification n = r.sbn;
3470                    final Notification notification = n.getNotification();
3471                    int index = indexOfNotificationLocked(n.getKey());
3472                    if (index < 0) {
3473                        mNotificationList.add(r);
3474                        mUsageStats.registerPostedByApp(r);
3475                    } else {
3476                        old = mNotificationList.get(index);
3477                        mNotificationList.set(index, r);
3478                        mUsageStats.registerUpdatedByApp(r, old);
3479                        // Make sure we don't lose the foreground service state.
3480                        notification.flags |=
3481                                old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3482                        r.isUpdate = true;
3483                    }
3484
3485                    mNotificationsByKey.put(n.getKey(), r);
3486
3487                    // Ensure if this is a foreground service that the proper additional
3488                    // flags are set.
3489                    if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3490                        notification.flags |= Notification.FLAG_ONGOING_EVENT
3491                                | Notification.FLAG_NO_CLEAR;
3492                    }
3493
3494                    applyZenModeLocked(r);
3495                    mRankingHelper.sort(mNotificationList);
3496
3497                    if (notification.getSmallIcon() != null) {
3498                        StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3499                        mListeners.notifyPostedLocked(n, oldSbn);
3500                        mHandler.post(new Runnable() {
3501                            @Override
3502                            public void run() {
3503                                mGroupHelper.onNotificationPosted(n);
3504                            }
3505                        });
3506                    } else {
3507                        Slog.e(TAG, "Not posting notification without small icon: " + notification);
3508                        if (old != null && !old.isCanceled) {
3509                            mListeners.notifyRemovedLocked(n,
3510                                    NotificationListenerService.REASON_ERROR);
3511                            mHandler.post(new Runnable() {
3512                                @Override
3513                                public void run() {
3514                                    mGroupHelper.onNotificationRemoved(n);
3515                                }
3516                            });
3517                        }
3518                        // ATTENTION: in a future release we will bail out here
3519                        // so that we do not play sounds, show lights, etc. for invalid
3520                        // notifications
3521                        Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3522                                + n.getPackageName());
3523                    }
3524
3525                    buzzBeepBlinkLocked(r);
3526                } finally {
3527                    int N = mEnqueuedNotifications.size();
3528                    for (int i = 0; i < N; i++) {
3529                        final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3530                        if (Objects.equals(key, enqueued.getKey())) {
3531                            mEnqueuedNotifications.remove(i);
3532                            break;
3533                        }
3534                    }
3535                }
3536            }
3537        }
3538    }
3539
3540    /**
3541     * Ensures that grouped notification receive their special treatment.
3542     *
3543     * <p>Cancels group children if the new notification causes a group to lose
3544     * its summary.</p>
3545     *
3546     * <p>Updates mSummaryByGroupKey.</p>
3547     */
3548    private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3549            int callingUid, int callingPid) {
3550        StatusBarNotification sbn = r.sbn;
3551        Notification n = sbn.getNotification();
3552        if (n.isGroupSummary() && !sbn.isAppGroup())  {
3553            // notifications without a group shouldn't be a summary, otherwise autobundling can
3554            // lead to bugs
3555            n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3556        }
3557
3558        String group = sbn.getGroupKey();
3559        boolean isSummary = n.isGroupSummary();
3560
3561        Notification oldN = old != null ? old.sbn.getNotification() : null;
3562        String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3563        boolean oldIsSummary = old != null && oldN.isGroupSummary();
3564
3565        if (oldIsSummary) {
3566            NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3567            if (removedSummary != old) {
3568                String removedKey =
3569                        removedSummary != null ? removedSummary.getKey() : "<null>";
3570                Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3571                        ", removed=" + removedKey);
3572            }
3573        }
3574        if (isSummary) {
3575            mSummaryByGroupKey.put(group, r);
3576        }
3577
3578        // Clear out group children of the old notification if the update
3579        // causes the group summary to go away. This happens when the old
3580        // notification was a summary and the new one isn't, or when the old
3581        // notification was a summary and its group key changed.
3582        if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
3583            cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
3584        }
3585    }
3586
3587    @VisibleForTesting
3588    void scheduleTimeoutLocked(NotificationRecord record) {
3589        if (record.getNotification().getTimeout() > 0) {
3590            final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3591                    REQUEST_CODE_TIMEOUT,
3592                    new Intent(ACTION_NOTIFICATION_TIMEOUT)
3593                            .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3594                                    .appendPath(record.getKey()).build())
3595                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3596                            .putExtra(EXTRA_KEY, record.getKey()),
3597                    PendingIntent.FLAG_UPDATE_CURRENT);
3598            mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
3599                    SystemClock.elapsedRealtime() + record.getNotification().getTimeout(), pi);
3600        }
3601    }
3602
3603    @VisibleForTesting
3604    void buzzBeepBlinkLocked(NotificationRecord record) {
3605        boolean buzz = false;
3606        boolean beep = false;
3607        boolean blink = false;
3608
3609        final Notification notification = record.sbn.getNotification();
3610        final String key = record.getKey();
3611
3612        // Should this notification make noise, vibe, or use the LED?
3613        final boolean aboveThreshold =
3614                record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
3615        final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
3616        if (DBG)
3617            Slog.v(TAG,
3618                    "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
3619                            " intercept=" + record.isIntercepted()
3620            );
3621
3622        final int currentUser;
3623        final long token = Binder.clearCallingIdentity();
3624        try {
3625            currentUser = ActivityManager.getCurrentUser();
3626        } finally {
3627            Binder.restoreCallingIdentity(token);
3628        }
3629
3630        // If we're not supposed to beep, vibrate, etc. then don't.
3631        final String disableEffects = disableNotificationEffects(record);
3632        if (disableEffects != null) {
3633            ZenLog.traceDisableEffects(record, disableEffects);
3634        }
3635
3636        // Remember if this notification already owns the notification channels.
3637        boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3638        boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
3639
3640        // These are set inside the conditional if the notification is allowed to make noise.
3641        boolean hasValidVibrate = false;
3642        boolean hasValidSound = false;
3643        if (disableEffects == null
3644                && (record.getUserId() == UserHandle.USER_ALL ||
3645                    record.getUserId() == currentUser ||
3646                    mUserProfiles.isCurrentProfile(record.getUserId()))
3647                && canInterrupt
3648                && mSystemReady
3649                && mAudioManager != null) {
3650            if (DBG) Slog.v(TAG, "Interrupting!");
3651
3652            Uri soundUri = record.getSound();
3653            hasValidSound = (soundUri != null);
3654            long[] vibration = record.getVibration();
3655            // Demote sound to vibration if vibration missing & phone in vibration mode.
3656            if (vibration == null
3657                    && hasValidSound
3658                    && (mAudioManager.getRingerModeInternal()
3659                            == AudioManager.RINGER_MODE_VIBRATE)) {
3660                vibration = mFallbackVibrationPattern;
3661            }
3662            hasValidVibrate = vibration != null;
3663
3664            // We can alert, and we're allowed to alert, but if the developer asked us to only do
3665            // it once, and we already have, then don't.
3666            if (!(record.isUpdate
3667                    && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
3668
3669                sendAccessibilityEvent(notification, record.sbn.getPackageName());
3670                if (hasValidSound) {
3671                    mSoundNotificationKey = key;
3672                    beep = playSound(record, soundUri);
3673                }
3674                if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
3675                        == AudioManager.RINGER_MODE_SILENT)) {
3676                    mVibrateNotificationKey = key;
3677
3678                    buzz = playVibration(record, vibration);
3679                }
3680            }
3681        }
3682        // If a notification is updated to remove the actively playing sound or vibrate,
3683        // cancel that feedback now
3684        if (wasBeep && !hasValidSound) {
3685            clearSoundLocked();
3686        }
3687        if (wasBuzz && !hasValidVibrate) {
3688            clearVibrateLocked();
3689        }
3690
3691        // light
3692        // release the light
3693        boolean wasShowLights = mLights.remove(key);
3694        if (record.getLight() != null && aboveThreshold
3695                && ((record.getSuppressedVisualEffects()
3696                & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
3697            mLights.add(key);
3698            updateLightsLocked();
3699            if (mUseAttentionLight) {
3700                mAttentionLight.pulse();
3701            }
3702            blink = true;
3703        } else if (wasShowLights) {
3704            updateLightsLocked();
3705        }
3706        if (buzz || beep || blink) {
3707            if (((record.getSuppressedVisualEffects()
3708                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
3709                if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
3710            } else {
3711                MetricsLogger.action(record.getLogMaker()
3712                        .setCategory(MetricsEvent.NOTIFICATION_ALERT)
3713                        .setType(MetricsEvent.TYPE_OPEN)
3714                        .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
3715                EventLogTags.writeNotificationAlert(key,
3716                        buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
3717            }
3718        }
3719    }
3720
3721    private boolean playSound(final NotificationRecord record, Uri soundUri) {
3722        boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3723        // do not play notifications if there is a user of exclusive audio focus
3724        // or the device is in vibrate mode
3725        if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
3726                != AudioManager.RINGER_MODE_VIBRATE) {
3727            final long identity = Binder.clearCallingIdentity();
3728            try {
3729                final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
3730                if (player != null) {
3731                    if (DBG) Slog.v(TAG, "Playing sound " + soundUri
3732                            + " with attributes " + record.getAudioAttributes());
3733                    player.playAsync(soundUri, record.sbn.getUser(), looping,
3734                            record.getAudioAttributes());
3735                    return true;
3736                }
3737            } catch (RemoteException e) {
3738            } finally {
3739                Binder.restoreCallingIdentity(identity);
3740            }
3741        }
3742        return false;
3743    }
3744
3745    private boolean playVibration(final NotificationRecord record, long[] vibration) {
3746        // Escalate privileges so we can use the vibrator even if the
3747        // notifying app does not have the VIBRATE permission.
3748        long identity = Binder.clearCallingIdentity();
3749        try {
3750            final boolean insistent =
3751                (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
3752            final VibrationEffect effect = VibrationEffect.createWaveform(
3753                    vibration, insistent ? 0 : -1 /*repeatIndex*/);
3754            mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
3755                    effect, record.getAudioAttributes());
3756            return true;
3757        } catch (IllegalArgumentException e) {
3758            Slog.e(TAG, "Error creating vibration waveform with pattern: " +
3759                    Arrays.toString(vibration));
3760            return false;
3761        } finally{
3762            Binder.restoreCallingIdentity(identity);
3763        }
3764    }
3765
3766    void showNextToastLocked() {
3767        ToastRecord record = mToastQueue.get(0);
3768        while (record != null) {
3769            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
3770            try {
3771                record.callback.show(record.token);
3772                scheduleTimeoutLocked(record);
3773                return;
3774            } catch (RemoteException e) {
3775                Slog.w(TAG, "Object died trying to show notification " + record.callback
3776                        + " in package " + record.pkg);
3777                // remove it from the list and let the process die
3778                int index = mToastQueue.indexOf(record);
3779                if (index >= 0) {
3780                    mToastQueue.remove(index);
3781                }
3782                keepProcessAliveIfNeededLocked(record.pid);
3783                if (mToastQueue.size() > 0) {
3784                    record = mToastQueue.get(0);
3785                } else {
3786                    record = null;
3787                }
3788            }
3789        }
3790    }
3791
3792    void cancelToastLocked(int index) {
3793        ToastRecord record = mToastQueue.get(index);
3794        try {
3795            record.callback.hide();
3796        } catch (RemoteException e) {
3797            Slog.w(TAG, "Object died trying to hide notification " + record.callback
3798                    + " in package " + record.pkg);
3799            // don't worry about this, we're about to remove it from
3800            // the list anyway
3801        }
3802
3803        ToastRecord lastToast = mToastQueue.remove(index);
3804        mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
3805
3806        keepProcessAliveIfNeededLocked(record.pid);
3807        if (mToastQueue.size() > 0) {
3808            // Show the next one. If the callback fails, this will remove
3809            // it from the list, so don't assume that the list hasn't changed
3810            // after this point.
3811            showNextToastLocked();
3812        }
3813    }
3814
3815    private void scheduleTimeoutLocked(ToastRecord r)
3816    {
3817        mHandler.removeCallbacksAndMessages(r);
3818        Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3819        long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3820        mHandler.sendMessageDelayed(m, delay);
3821    }
3822
3823    private void handleTimeout(ToastRecord record)
3824    {
3825        if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3826        synchronized (mToastQueue) {
3827            int index = indexOfToastLocked(record.pkg, record.callback);
3828            if (index >= 0) {
3829                cancelToastLocked(index);
3830            }
3831        }
3832    }
3833
3834    // lock on mToastQueue
3835    int indexOfToastLocked(String pkg, ITransientNotification callback)
3836    {
3837        IBinder cbak = callback.asBinder();
3838        ArrayList<ToastRecord> list = mToastQueue;
3839        int len = list.size();
3840        for (int i=0; i<len; i++) {
3841            ToastRecord r = list.get(i);
3842            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3843                return i;
3844            }
3845        }
3846        return -1;
3847    }
3848
3849    // lock on mToastQueue
3850    void keepProcessAliveIfNeededLocked(int pid)
3851    {
3852        int toastCount = 0; // toasts from this pid
3853        ArrayList<ToastRecord> list = mToastQueue;
3854        int N = list.size();
3855        for (int i=0; i<N; i++) {
3856            ToastRecord r = list.get(i);
3857            if (r.pid == pid) {
3858                toastCount++;
3859            }
3860        }
3861        try {
3862            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3863        } catch (RemoteException e) {
3864            // Shouldn't happen.
3865        }
3866    }
3867
3868    private void handleRankingReconsideration(Message message) {
3869        if (!(message.obj instanceof RankingReconsideration)) return;
3870        RankingReconsideration recon = (RankingReconsideration) message.obj;
3871        recon.run();
3872        boolean changed;
3873        synchronized (mNotificationLock) {
3874            final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3875            if (record == null) {
3876                return;
3877            }
3878            int indexBefore = findNotificationRecordIndexLocked(record);
3879            boolean interceptBefore = record.isIntercepted();
3880            int visibilityBefore = record.getPackageVisibilityOverride();
3881            recon.applyChangesLocked(record);
3882            applyZenModeLocked(record);
3883            mRankingHelper.sort(mNotificationList);
3884            int indexAfter = findNotificationRecordIndexLocked(record);
3885            boolean interceptAfter = record.isIntercepted();
3886            int visibilityAfter = record.getPackageVisibilityOverride();
3887            changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3888                    || visibilityBefore != visibilityAfter;
3889            if (interceptBefore && !interceptAfter) {
3890                buzzBeepBlinkLocked(record);
3891            }
3892        }
3893        if (changed) {
3894            scheduleSendRankingUpdate();
3895        }
3896    }
3897
3898    private void handleRankingSort(Message msg) {
3899        if (!(msg.obj instanceof Boolean)) return;
3900        boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
3901        synchronized (mNotificationLock) {
3902            final int N = mNotificationList.size();
3903            // Any field that can change via one of the extractors or by the assistant
3904            // needs to be added here.
3905            ArrayList<String> orderBefore = new ArrayList<String>(N);
3906            ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
3907            int[] visibilities = new int[N];
3908            boolean[] showBadges = new boolean[N];
3909            for (int i = 0; i < N; i++) {
3910                final NotificationRecord r = mNotificationList.get(i);
3911                orderBefore.add(r.getKey());
3912                groupOverrideBefore.add(r.sbn.getGroupKey());
3913                visibilities[i] = r.getPackageVisibilityOverride();
3914                showBadges[i] = r.canShowBadge();
3915                mRankingHelper.extractSignals(r);
3916            }
3917            mRankingHelper.sort(mNotificationList);
3918            for (int i = 0; i < N; i++) {
3919                final NotificationRecord r = mNotificationList.get(i);
3920                if (forceUpdate
3921                        || !orderBefore.get(i).equals(r.getKey())
3922                        || visibilities[i] != r.getPackageVisibilityOverride()
3923                        || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
3924                        || showBadges[i] != r.canShowBadge()) {
3925                    scheduleSendRankingUpdate();
3926                    return;
3927                }
3928            }
3929        }
3930    }
3931
3932    private void recordCallerLocked(NotificationRecord record) {
3933        if (mZenModeHelper.isCall(record)) {
3934            mZenModeHelper.recordCaller(record);
3935        }
3936    }
3937
3938    // let zen mode evaluate this record
3939    private void applyZenModeLocked(NotificationRecord record) {
3940        record.setIntercepted(mZenModeHelper.shouldIntercept(record));
3941        if (record.isIntercepted()) {
3942            int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3943                    ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3944                    | (mZenModeHelper.shouldSuppressWhenScreenOn()
3945                    ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
3946            record.setSuppressedVisualEffects(suppressed);
3947        }
3948    }
3949
3950    // lock on mNotificationList
3951    private int findNotificationRecordIndexLocked(NotificationRecord target) {
3952        return mRankingHelper.indexOf(mNotificationList, target);
3953    }
3954
3955    private void scheduleSendRankingUpdate() {
3956        if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3957            Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3958            mHandler.sendMessage(m);
3959        }
3960    }
3961
3962    private void handleSendRankingUpdate() {
3963        synchronized (mNotificationLock) {
3964            mListeners.notifyRankingUpdateLocked();
3965        }
3966    }
3967
3968    private void scheduleListenerHintsChanged(int state) {
3969        mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3970        mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
3971    }
3972
3973    private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3974        mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3975        mHandler.obtainMessage(
3976                MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3977                listenerInterruptionFilter,
3978                0).sendToTarget();
3979    }
3980
3981    private void handleListenerHintsChanged(int hints) {
3982        synchronized (mNotificationLock) {
3983            mListeners.notifyListenerHintsChangedLocked(hints);
3984        }
3985    }
3986
3987    private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3988        synchronized (mNotificationLock) {
3989            mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3990        }
3991    }
3992
3993    private final class WorkerHandler extends Handler
3994    {
3995        public WorkerHandler(Looper looper) {
3996            super(looper);
3997        }
3998
3999        @Override
4000        public void handleMessage(Message msg)
4001        {
4002            switch (msg.what)
4003            {
4004                case MESSAGE_TIMEOUT:
4005                    handleTimeout((ToastRecord)msg.obj);
4006                    break;
4007                case MESSAGE_SAVE_POLICY_FILE:
4008                    handleSavePolicyFile();
4009                    break;
4010                case MESSAGE_SEND_RANKING_UPDATE:
4011                    handleSendRankingUpdate();
4012                    break;
4013                case MESSAGE_LISTENER_HINTS_CHANGED:
4014                    handleListenerHintsChanged(msg.arg1);
4015                    break;
4016                case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4017                    handleListenerInterruptionFilterChanged(msg.arg1);
4018                    break;
4019            }
4020        }
4021
4022    }
4023
4024    private final class RankingHandlerWorker extends Handler implements RankingHandler
4025    {
4026        public RankingHandlerWorker(Looper looper) {
4027            super(looper);
4028        }
4029
4030        @Override
4031        public void handleMessage(Message msg) {
4032            switch (msg.what) {
4033                case MESSAGE_RECONSIDER_RANKING:
4034                    handleRankingReconsideration(msg);
4035                    break;
4036                case MESSAGE_RANKING_SORT:
4037                    handleRankingSort(msg);
4038                    break;
4039            }
4040        }
4041
4042        public void requestSort(boolean forceUpdate) {
4043            removeMessages(MESSAGE_RANKING_SORT);
4044            Message msg = Message.obtain();
4045            msg.what = MESSAGE_RANKING_SORT;
4046            msg.obj = forceUpdate;
4047            sendMessage(msg);
4048        }
4049
4050        public void requestReconsideration(RankingReconsideration recon) {
4051            Message m = Message.obtain(this,
4052                    NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4053            long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4054            sendMessageDelayed(m, delay);
4055        }
4056    }
4057
4058    // Notifications
4059    // ============================================================================
4060    static int clamp(int x, int low, int high) {
4061        return (x < low) ? low : ((x > high) ? high : x);
4062    }
4063
4064    void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4065        AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
4066        if (!manager.isEnabled()) {
4067            return;
4068        }
4069
4070        AccessibilityEvent event =
4071            AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4072        event.setPackageName(packageName);
4073        event.setClassName(Notification.class.getName());
4074        event.setParcelableData(notification);
4075        CharSequence tickerText = notification.tickerText;
4076        if (!TextUtils.isEmpty(tickerText)) {
4077            event.getText().add(tickerText);
4078        }
4079
4080        manager.sendAccessibilityEvent(event);
4081    }
4082
4083    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
4084        final String canceledKey = r.getKey();
4085
4086        // Remove from both lists, either list could have a separate Record for what is effectively
4087        // the same notification.
4088        boolean wasPosted = false;
4089        NotificationRecord recordInList = null;
4090        if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey())) != null) {
4091            mNotificationList.remove(recordInList);
4092            mNotificationsByKey.remove(recordInList.sbn.getKey());
4093            wasPosted = true;
4094        }
4095        if ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
4096                != null) {
4097            mEnqueuedNotifications.remove(recordInList);
4098        }
4099
4100        // Record caller.
4101        recordCallerLocked(r);
4102
4103        // tell the app
4104        if (sendDelete) {
4105            if (r.getNotification().deleteIntent != null) {
4106                try {
4107                    r.getNotification().deleteIntent.send();
4108                } catch (PendingIntent.CanceledException ex) {
4109                    // do nothing - there's no relevant way to recover, and
4110                    //     no reason to let this propagate
4111                    Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
4112                }
4113            }
4114        }
4115
4116        // Only cancel these if this notification actually got to be posted.
4117        if (wasPosted) {
4118            // status bar
4119            if (r.getNotification().getSmallIcon() != null) {
4120                r.isCanceled = true;
4121                mListeners.notifyRemovedLocked(r.sbn, reason);
4122                mHandler.post(new Runnable() {
4123                    @Override
4124                    public void run() {
4125                        mGroupHelper.onNotificationRemoved(r.sbn);
4126                    }
4127                });
4128            }
4129
4130            // sound
4131            if (canceledKey.equals(mSoundNotificationKey)) {
4132                mSoundNotificationKey = null;
4133                final long identity = Binder.clearCallingIdentity();
4134                try {
4135                    final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4136                    if (player != null) {
4137                        player.stopAsync();
4138                    }
4139                } catch (RemoteException e) {
4140                } finally {
4141                    Binder.restoreCallingIdentity(identity);
4142                }
4143            }
4144
4145            // vibrate
4146            if (canceledKey.equals(mVibrateNotificationKey)) {
4147                mVibrateNotificationKey = null;
4148                long identity = Binder.clearCallingIdentity();
4149                try {
4150                    mVibrator.cancel();
4151                }
4152                finally {
4153                    Binder.restoreCallingIdentity(identity);
4154                }
4155            }
4156
4157            // light
4158            mLights.remove(canceledKey);
4159        }
4160
4161        // Record usage stats
4162        // TODO: add unbundling stats?
4163        switch (reason) {
4164            case REASON_CANCEL:
4165            case REASON_CANCEL_ALL:
4166            case REASON_LISTENER_CANCEL:
4167            case REASON_LISTENER_CANCEL_ALL:
4168                mUsageStats.registerDismissedByUser(r);
4169                break;
4170            case REASON_APP_CANCEL:
4171            case REASON_APP_CANCEL_ALL:
4172                mUsageStats.registerRemovedByApp(r);
4173                break;
4174        }
4175
4176        String groupKey = r.getGroupKey();
4177        NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
4178        if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
4179            mSummaryByGroupKey.remove(groupKey);
4180        }
4181        final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4182        if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4183            summaries.remove(r.sbn.getPackageName());
4184        }
4185
4186        // Save it for users of getHistoricalNotifications()
4187        mArchive.record(r.sbn);
4188
4189        final long now = System.currentTimeMillis();
4190        MetricsLogger.action(r.getLogMaker(now)
4191                .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4192                .setType(MetricsEvent.TYPE_DISMISS)
4193                .setSubtype(reason));
4194        EventLogTags.writeNotificationCanceled(canceledKey, reason,
4195                r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
4196    }
4197
4198    /**
4199     * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
4200     * and none of the {@code mustNotHaveFlags}.
4201     */
4202    void cancelNotification(final int callingUid, final int callingPid,
4203            final String pkg, final String tag, final int id,
4204            final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
4205            final int userId, final int reason, final ManagedServiceInfo listener) {
4206        // In enqueueNotificationInternal notifications are added by scheduling the
4207        // work on the worker handler. Hence, we also schedule the cancel on this
4208        // handler to avoid a scenario where an add notification call followed by a
4209        // remove notification call ends up in not removing the notification.
4210        mHandler.post(new Runnable() {
4211            @Override
4212            public void run() {
4213                String listenerName = listener == null ? null : listener.component.toShortString();
4214                if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4215                        userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
4216
4217                synchronized (mNotificationLock) {
4218                    // Look for the notification, searching both the posted and enqueued lists.
4219                    NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4220                    if (r != null) {
4221                        // The notification was found, check if it should be removed.
4222
4223                        // Ideally we'd do this in the caller of this method. However, that would
4224                        // require the caller to also find the notification.
4225                        if (reason == REASON_CLICK) {
4226                            mUsageStats.registerClickedByUser(r);
4227                        }
4228
4229                        if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4230                            return;
4231                        }
4232                        if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4233                            return;
4234                        }
4235
4236                        // Cancel the notification.
4237                        cancelNotificationLocked(r, sendDelete, reason);
4238                        cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
4239                                sendDelete);
4240                        updateLightsLocked();
4241                    } else {
4242                        // No notification was found, assume that it is snoozed and cancel it.
4243                        final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4244                        if (wasSnoozed) {
4245                            savePolicyFile();
4246                        }
4247                    }
4248                }
4249            }
4250        });
4251    }
4252
4253    /**
4254     * Determine whether the userId applies to the notification in question, either because
4255     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4256     */
4257    private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4258        return
4259                // looking for USER_ALL notifications? match everything
4260                   userId == UserHandle.USER_ALL
4261                // a notification sent to USER_ALL matches any query
4262                || r.getUserId() == UserHandle.USER_ALL
4263                // an exact user match
4264                || r.getUserId() == userId;
4265    }
4266
4267    /**
4268     * Determine whether the userId applies to the notification in question, either because
4269     * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
4270     * because it matches one of the users profiles.
4271     */
4272    private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
4273        return notificationMatchesUserId(r, userId)
4274                || mUserProfiles.isCurrentProfile(r.getUserId());
4275    }
4276
4277    /**
4278     * Cancels all notifications from a given package that have all of the
4279     * {@code mustHaveFlags}.
4280     */
4281    void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
4282            int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
4283            ManagedServiceInfo listener) {
4284        mHandler.post(new Runnable() {
4285            @Override
4286            public void run() {
4287                String listenerName = listener == null ? null : listener.component.toShortString();
4288                EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4289                        pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4290                        listenerName);
4291
4292                // Why does this parameter exist? Do we actually want to execute the above if doit
4293                // is false?
4294                if (!doit) {
4295                    return;
4296                }
4297
4298                synchronized (mNotificationLock) {
4299                    FlagChecker flagChecker = (int flags) -> {
4300                        if ((flags & mustHaveFlags) != mustHaveFlags) {
4301                            return false;
4302                        }
4303                        if ((flags & mustNotHaveFlags) != 0) {
4304                            return false;
4305                        }
4306                        return true;
4307                    };
4308
4309                    cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4310                            pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4311                            false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
4312                            listenerName);
4313                    cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4314                            callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4315                            flagChecker, false /*includeCurrentProfiles*/, userId,
4316                            false /*sendDelete*/, reason, listenerName);
4317                    mSnoozeHelper.cancel(userId, pkg);
4318                }
4319            }
4320        });
4321    }
4322
4323    private interface FlagChecker {
4324        // Returns false if these flags do not pass the defined flag test.
4325        public boolean apply(int flags);
4326    }
4327
4328    private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4329            int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4330            String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
4331            boolean sendDelete, int reason, String listenerName) {
4332        ArrayList<NotificationRecord> canceledNotifications = null;
4333        for (int i = notificationList.size() - 1; i >= 0; --i) {
4334            NotificationRecord r = notificationList.get(i);
4335            if (includeCurrentProfiles) {
4336                if (!notificationMatchesCurrentProfiles(r, userId)) {
4337                    continue;
4338                }
4339            } else if (!notificationMatchesUserId(r, userId)) {
4340                continue;
4341            }
4342            // Don't remove notifications to all, if there's no package name specified
4343            if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4344                continue;
4345            }
4346            if (!flagChecker.apply(r.getFlags())) {
4347                continue;
4348            }
4349            if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4350                continue;
4351            }
4352            if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4353                continue;
4354            }
4355
4356            if (canceledNotifications == null) {
4357                canceledNotifications = new ArrayList<>();
4358            }
4359            canceledNotifications.add(r);
4360            cancelNotificationLocked(r, sendDelete, reason);
4361        }
4362        if (canceledNotifications != null) {
4363            final int M = canceledNotifications.size();
4364            for (int i = 0; i < M; i++) {
4365                cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
4366                        listenerName, false /* sendDelete */);
4367            }
4368            updateLightsLocked();
4369        }
4370    }
4371
4372    void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
4373            ManagedServiceInfo listener) {
4374        String listenerName = listener == null ? null : listener.component.toShortString();
4375        if (duration <= 0 && snoozeCriterionId == null) {
4376            return;
4377        }
4378
4379        if (DBG) {
4380            Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4381                    snoozeCriterionId, listenerName));
4382        }
4383        // Needs to post so that it can cancel notifications not yet enqueued.
4384        mHandler.post(new Runnable() {
4385            @Override
4386            public void run() {
4387                synchronized (mNotificationLock) {
4388                    final NotificationRecord r = findNotificationByKeyLocked(key);
4389                    if (r != null) {
4390                        MetricsLogger.action(r.getLogMaker()
4391                                .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4392                                .setType(MetricsEvent.TYPE_CLOSE)
4393                                .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4394                                        snoozeCriterionId == null ? 0 : 1));
4395                        cancelNotificationLocked(r, false, REASON_SNOOZED);
4396                        updateLightsLocked();
4397                        if (snoozeCriterionId != null) {
4398                            mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn,
4399                                    snoozeCriterionId);
4400                            mSnoozeHelper.snooze(r);
4401                        } else {
4402                            mSnoozeHelper.snooze(r, duration);
4403                        }
4404                        savePolicyFile();
4405                    }
4406                }
4407            }
4408        });
4409    }
4410
4411    void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4412        String listenerName = listener == null ? null : listener.component.toShortString();
4413        if (DBG) {
4414            Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4415        }
4416        mSnoozeHelper.repost(key);
4417        savePolicyFile();
4418    }
4419
4420    void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
4421            ManagedServiceInfo listener, boolean includeCurrentProfiles) {
4422        mHandler.post(new Runnable() {
4423            @Override
4424            public void run() {
4425                synchronized (mNotificationLock) {
4426                    String listenerName =
4427                            listener == null ? null : listener.component.toShortString();
4428                    EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4429                            null, userId, 0, 0, reason, listenerName);
4430
4431                    FlagChecker flagChecker = (int flags) -> {
4432                        if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4433                                != 0) {
4434                            return false;
4435                        }
4436                        return true;
4437                    };
4438
4439                    cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4440                            null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4441                            includeCurrentProfiles, userId, true /*sendDelete*/, reason,
4442                            listenerName);
4443                    cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4444                            callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4445                            flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
4446                            reason, listenerName);
4447                    mSnoozeHelper.cancel(userId, includeCurrentProfiles);
4448                }
4449            }
4450        });
4451    }
4452
4453    // Warning: The caller is responsible for invoking updateLightsLocked().
4454    private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
4455            String listenerName, boolean sendDelete) {
4456        Notification n = r.getNotification();
4457        if (!n.isGroupSummary()) {
4458            return;
4459        }
4460
4461        String pkg = r.sbn.getPackageName();
4462        int userId = r.getUserId();
4463
4464        if (pkg == null) {
4465            if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4466            return;
4467        }
4468
4469        cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
4470                sendDelete);
4471        cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
4472                listenerName, sendDelete);
4473    }
4474
4475    private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4476            NotificationRecord parentNotification, int callingUid, int callingPid,
4477            String listenerName, boolean sendDelete) {
4478        final String pkg = parentNotification.sbn.getPackageName();
4479        final int userId = parentNotification.getUserId();
4480        final int reason = REASON_GROUP_SUMMARY_CANCELED;
4481        for (int i = notificationList.size() - 1; i >= 0; i--) {
4482            final NotificationRecord childR = notificationList.get(i);
4483            final StatusBarNotification childSbn = childR.sbn;
4484            if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
4485                    childR.getGroupKey().equals(parentNotification.getGroupKey())
4486                    && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
4487                EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4488                        childSbn.getTag(), userId, 0, 0, reason, listenerName);
4489                cancelNotificationLocked(childR, sendDelete, reason);
4490            }
4491        }
4492    }
4493
4494    // lock on mNotificationList
4495    void updateLightsLocked()
4496    {
4497        // handle notification lights
4498        NotificationRecord ledNotification = null;
4499        while (ledNotification == null && !mLights.isEmpty()) {
4500            final String owner = mLights.get(mLights.size() - 1);
4501            ledNotification = mNotificationsByKey.get(owner);
4502            if (ledNotification == null) {
4503                Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4504                mLights.remove(owner);
4505            }
4506        }
4507
4508        // Don't flash while we are in a call or screen is on
4509        if (ledNotification == null || mInCall || mScreenOn) {
4510            mNotificationLight.turnOff();
4511        } else {
4512            NotificationRecord.Light light = ledNotification.getLight();
4513            if (light != null && mNotificationPulseEnabled) {
4514                // pulse repeatedly
4515                mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4516                        light.onMs, light.offMs);
4517            }
4518        }
4519    }
4520
4521    // Searches both enqueued and posted notifications by key.
4522    // TODO: need to combine a bunch of these getters with slightly different behavior.
4523    // TODO: Should enqueuing just add to mNotificationsByKey instead?
4524    private NotificationRecord findNotificationByKeyLocked(String key) {
4525        NotificationRecord r;
4526        if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4527            return r;
4528        }
4529        if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4530            return r;
4531        }
4532        return null;
4533    }
4534
4535    private NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
4536        NotificationRecord r;
4537        if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4538            return r;
4539        }
4540        if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4541                != null) {
4542            return r;
4543        }
4544        return null;
4545    }
4546
4547    private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4548            String pkg, String tag, int id, int userId) {
4549        final int len = list.size();
4550        for (int i = 0; i < len; i++) {
4551            NotificationRecord r = list.get(i);
4552            if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
4553                    TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
4554                return r;
4555            }
4556        }
4557        return null;
4558    }
4559
4560    private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
4561            String key)
4562    {
4563        final int N = list.size();
4564        for (int i = 0; i < N; i++) {
4565            if (key.equals(list.get(i).getKey())) {
4566                return list.get(i);
4567            }
4568        }
4569        return null;
4570    }
4571
4572    // lock on mNotificationList
4573    int indexOfNotificationLocked(String key) {
4574        final int N = mNotificationList.size();
4575        for (int i = 0; i < N; i++) {
4576            if (key.equals(mNotificationList.get(i).getKey())) {
4577                return i;
4578            }
4579        }
4580        return -1;
4581    }
4582
4583    private void updateNotificationPulse() {
4584        synchronized (mNotificationLock) {
4585            updateLightsLocked();
4586        }
4587    }
4588
4589    protected boolean isUidSystem(int uid) {
4590        final int appid = UserHandle.getAppId(uid);
4591        return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
4592    }
4593
4594    protected boolean isCallerSystem() {
4595        return isUidSystem(Binder.getCallingUid());
4596    }
4597
4598    private void checkCallerIsSystem() {
4599        if (isCallerSystem()) {
4600            return;
4601        }
4602        throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
4603    }
4604
4605    private void checkCallerIsSystemOrSameApp(String pkg) {
4606        if (isCallerSystem()) {
4607            return;
4608        }
4609        checkCallerIsSameApp(pkg);
4610    }
4611
4612    private boolean isCallerInstantApp(String pkg) {
4613        // System is always allowed to act for ephemeral apps.
4614        if (isCallerSystem()) {
4615            return false;
4616        }
4617
4618        mAppOps.checkPackage(Binder.getCallingUid(), pkg);
4619
4620        try {
4621            ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
4622                    UserHandle.getCallingUserId());
4623            if (ai == null) {
4624                throw new SecurityException("Unknown package " + pkg);
4625            }
4626            return ai.isInstantApp();
4627        } catch (RemoteException re) {
4628            throw new SecurityException("Unknown package " + pkg, re);
4629        }
4630
4631    }
4632
4633    private void checkCallerIsSameApp(String pkg) {
4634        final int uid = Binder.getCallingUid();
4635        try {
4636            ApplicationInfo ai = mPackageManager.getApplicationInfo(
4637                    pkg, 0, UserHandle.getCallingUserId());
4638            if (ai == null) {
4639                throw new SecurityException("Unknown package " + pkg);
4640            }
4641            if (!UserHandle.isSameApp(ai.uid, uid)) {
4642                throw new SecurityException("Calling uid " + uid + " gave package "
4643                        + pkg + " which is owned by uid " + ai.uid);
4644            }
4645        } catch (RemoteException re) {
4646            throw new SecurityException("Unknown package " + pkg + "\n" + re);
4647        }
4648    }
4649
4650    private static String callStateToString(int state) {
4651        switch (state) {
4652            case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
4653            case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
4654            case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
4655            default: return "CALL_STATE_UNKNOWN_" + state;
4656        }
4657    }
4658
4659    private void listenForCallState() {
4660        TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
4661            @Override
4662            public void onCallStateChanged(int state, String incomingNumber) {
4663                if (mCallState == state) return;
4664                if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
4665                mCallState = state;
4666            }
4667        }, PhoneStateListener.LISTEN_CALL_STATE);
4668    }
4669
4670    /**
4671     * Generates a NotificationRankingUpdate from 'sbns', considering only
4672     * notifications visible to the given listener.
4673     *
4674     * <p>Caller must hold a lock on mNotificationList.</p>
4675     */
4676    private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
4677        final int N = mNotificationList.size();
4678        ArrayList<String> keys = new ArrayList<String>(N);
4679        ArrayList<String> interceptedKeys = new ArrayList<String>(N);
4680        ArrayList<Integer> importance = new ArrayList<>(N);
4681        Bundle overrideGroupKeys = new Bundle();
4682        Bundle visibilityOverrides = new Bundle();
4683        Bundle suppressedVisualEffects = new Bundle();
4684        Bundle explanation = new Bundle();
4685        Bundle channels = new Bundle();
4686        Bundle overridePeople = new Bundle();
4687        Bundle snoozeCriteria = new Bundle();
4688        Bundle showBadge = new Bundle();
4689        for (int i = 0; i < N; i++) {
4690            NotificationRecord record = mNotificationList.get(i);
4691            if (!isVisibleToListener(record.sbn, info)) {
4692                continue;
4693            }
4694            final String key = record.sbn.getKey();
4695            keys.add(key);
4696            importance.add(record.getImportance());
4697            if (record.getImportanceExplanation() != null) {
4698                explanation.putCharSequence(key, record.getImportanceExplanation());
4699            }
4700            if (record.isIntercepted()) {
4701                interceptedKeys.add(key);
4702
4703            }
4704            suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
4705            if (record.getPackageVisibilityOverride()
4706                    != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
4707                visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
4708            }
4709            overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
4710            channels.putParcelable(key, record.getChannel());
4711            overridePeople.putStringArrayList(key, record.getPeopleOverride());
4712            snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
4713            showBadge.putBoolean(key, record.canShowBadge());
4714        }
4715        final int M = keys.size();
4716        String[] keysAr = keys.toArray(new String[M]);
4717        String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
4718        int[] importanceAr = new int[M];
4719        for (int i = 0; i < M; i++) {
4720            importanceAr[i] = importance.get(i);
4721        }
4722        return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
4723                suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
4724                channels, overridePeople, snoozeCriteria, showBadge);
4725    }
4726
4727    boolean hasCompanionDevice(ManagedServiceInfo info) {
4728        if (mCompanionManager == null) {
4729            mCompanionManager = getCompanionManager();
4730        }
4731        // Companion mgr doesn't exist on all device types
4732        if (mCompanionManager == null) {
4733            return false;
4734        }
4735        long identity = Binder.clearCallingIdentity();
4736        try {
4737            List<String> associations = mCompanionManager.getAssociations(
4738                    info.component.getPackageName(), info.userid);
4739            if (!ArrayUtils.isEmpty(associations)) {
4740                return true;
4741            }
4742        } catch (SecurityException se) {
4743            // Not a privileged listener
4744        } catch (RemoteException re) {
4745            Slog.e(TAG, "Cannot reach companion device service", re);
4746        } catch (Exception e) {
4747            Slog.e(TAG, "Cannot verify listener " + info, e);
4748        } finally {
4749            Binder.restoreCallingIdentity(identity);
4750        }
4751        return false;
4752    }
4753
4754    protected ICompanionDeviceManager getCompanionManager() {
4755        return ICompanionDeviceManager.Stub.asInterface(
4756                ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
4757    }
4758
4759    private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
4760        if (!listener.enabledAndUserMatches(sbn.getUserId())) {
4761            return false;
4762        }
4763        // TODO: remove this for older listeners.
4764        return true;
4765    }
4766
4767    private boolean isPackageSuspendedForUser(String pkg, int uid) {
4768        int userId = UserHandle.getUserId(uid);
4769        try {
4770            return mPackageManager.isPackageSuspendedForUser(pkg, userId);
4771        } catch (RemoteException re) {
4772            throw new SecurityException("Could not talk to package manager service");
4773        } catch (IllegalArgumentException ex) {
4774            // Package not found.
4775            return false;
4776        }
4777    }
4778
4779    private class TrimCache {
4780        StatusBarNotification heavy;
4781        StatusBarNotification sbnClone;
4782        StatusBarNotification sbnCloneLight;
4783
4784        TrimCache(StatusBarNotification sbn) {
4785            heavy = sbn;
4786        }
4787
4788        StatusBarNotification ForListener(ManagedServiceInfo info) {
4789            if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
4790                if (sbnCloneLight == null) {
4791                    sbnCloneLight = heavy.cloneLight();
4792                }
4793                return sbnCloneLight;
4794            } else {
4795                if (sbnClone == null) {
4796                    sbnClone = heavy.clone();
4797                }
4798                return sbnClone;
4799            }
4800        }
4801    }
4802
4803    public class NotificationAssistants extends ManagedServices {
4804
4805        public NotificationAssistants() {
4806            super(getContext(), mHandler, mNotificationList, mUserProfiles);
4807        }
4808
4809        @Override
4810        protected Config getConfig() {
4811            Config c = new Config();
4812            c.caption = "notification assistant service";
4813            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
4814            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
4815            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
4816            c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
4817            c.clientLabel = R.string.notification_ranker_binding_label;
4818            return c;
4819        }
4820
4821        @Override
4822        protected IInterface asInterface(IBinder binder) {
4823            return INotificationListener.Stub.asInterface(binder);
4824        }
4825
4826        @Override
4827        protected boolean checkType(IInterface service) {
4828            return service instanceof INotificationListener;
4829        }
4830
4831        @Override
4832        protected void onServiceAdded(ManagedServiceInfo info) {
4833            mListeners.registerGuestService(info);
4834        }
4835
4836        @Override
4837        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
4838            mListeners.unregisterService(removed.service, removed.userid);
4839        }
4840
4841        public void onNotificationEnqueued(final NotificationRecord r) {
4842            final StatusBarNotification sbn = r.sbn;
4843            TrimCache trimCache = new TrimCache(sbn);
4844
4845            // There should be only one, but it's a list, so while we enforce
4846            // singularity elsewhere, we keep it general here, to avoid surprises.
4847            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
4848                boolean sbnVisible = isVisibleToListener(sbn, info);
4849                if (!sbnVisible) {
4850                    continue;
4851                }
4852
4853                final int importance = r.getImportance();
4854                final boolean fromUser = r.isImportanceFromUser();
4855                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4856                mHandler.post(new Runnable() {
4857                    @Override
4858                    public void run() {
4859                        notifyEnqueued(info, sbnToPost);
4860                    }
4861                });
4862            }
4863        }
4864
4865        private void notifyEnqueued(final ManagedServiceInfo info,
4866                final StatusBarNotification sbn) {
4867            final INotificationListener assistant = (INotificationListener) info.service;
4868            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
4869            try {
4870                assistant.onNotificationEnqueued(sbnHolder);
4871            } catch (RemoteException ex) {
4872                Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
4873            }
4874        }
4875
4876        /**
4877         * asynchronously notify the assistant that a notification has been snoozed until a
4878         * context
4879         */
4880        public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
4881                final String snoozeCriterionId) {
4882            TrimCache trimCache = new TrimCache(sbn);
4883            for (final ManagedServiceInfo info : getServices()) {
4884                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
4885                mHandler.post(new Runnable() {
4886                    @Override
4887                    public void run() {
4888                        final INotificationListener assistant =
4889                                (INotificationListener) info.service;
4890                        StatusBarNotificationHolder sbnHolder
4891                                = new StatusBarNotificationHolder(sbnToPost);
4892                        try {
4893                            assistant.onNotificationSnoozedUntilContext(
4894                                    sbnHolder, snoozeCriterionId);
4895                        } catch (RemoteException ex) {
4896                            Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
4897                        }
4898                    }
4899                });
4900            }
4901        }
4902
4903        public boolean isEnabled() {
4904            return !getServices().isEmpty();
4905        }
4906    }
4907
4908    public class NotificationListeners extends ManagedServices {
4909
4910        private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
4911
4912        public NotificationListeners() {
4913            super(getContext(), mHandler, mNotificationList, mUserProfiles);
4914        }
4915
4916        @Override
4917        protected Config getConfig() {
4918            Config c = new Config();
4919            c.caption = "notification listener";
4920            c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
4921            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
4922            c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
4923            c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
4924            c.clientLabel = R.string.notification_listener_binding_label;
4925            return c;
4926        }
4927
4928        @Override
4929        protected IInterface asInterface(IBinder binder) {
4930            return INotificationListener.Stub.asInterface(binder);
4931        }
4932
4933        @Override
4934        protected boolean checkType(IInterface service) {
4935            return service instanceof INotificationListener;
4936        }
4937
4938        @Override
4939        public void onServiceAdded(ManagedServiceInfo info) {
4940            final INotificationListener listener = (INotificationListener) info.service;
4941            final NotificationRankingUpdate update;
4942            synchronized (mNotificationLock) {
4943                update = makeRankingUpdateLocked(info);
4944            }
4945            try {
4946                listener.onListenerConnected(update);
4947            } catch (RemoteException e) {
4948                // we tried
4949            }
4950        }
4951
4952        @Override
4953        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
4954            if (removeDisabledHints(removed)) {
4955                updateListenerHintsLocked();
4956                updateEffectsSuppressorLocked();
4957            }
4958            mLightTrimListeners.remove(removed);
4959        }
4960
4961        public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
4962            if (trim == TRIM_LIGHT) {
4963                mLightTrimListeners.add(info);
4964            } else {
4965                mLightTrimListeners.remove(info);
4966            }
4967        }
4968
4969        public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
4970            return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
4971        }
4972
4973        /**
4974         * asynchronously notify all listeners about a new notification
4975         *
4976         * <p>
4977         * Also takes care of removing a notification that has been visible to a listener before,
4978         * but isn't anymore.
4979         */
4980        public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
4981            // Lazily initialized snapshots of the notification.
4982            TrimCache trimCache = new TrimCache(sbn);
4983
4984            for (final ManagedServiceInfo info : getServices()) {
4985                boolean sbnVisible = isVisibleToListener(sbn, info);
4986                boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
4987                // This notification hasn't been and still isn't visible -> ignore.
4988                if (!oldSbnVisible && !sbnVisible) {
4989                    continue;
4990                }
4991                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
4992
4993                // This notification became invisible -> remove the old one.
4994                if (oldSbnVisible && !sbnVisible) {
4995                    final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4996                    mHandler.post(new Runnable() {
4997                        @Override
4998                        public void run() {
4999                            notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
5000                        }
5001                    });
5002                    continue;
5003                }
5004
5005                final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
5006                mHandler.post(new Runnable() {
5007                    @Override
5008                    public void run() {
5009                        notifyPosted(info, sbnToPost, update);
5010                    }
5011                });
5012            }
5013        }
5014
5015        /**
5016         * asynchronously notify all listeners about a removed notification
5017         */
5018        public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
5019            // make a copy in case changes are made to the underlying Notification object
5020            // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5021            // notification
5022            final StatusBarNotification sbnLight = sbn.cloneLight();
5023            for (final ManagedServiceInfo info : getServices()) {
5024                if (!isVisibleToListener(sbn, info)) {
5025                    continue;
5026                }
5027                final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
5028                mHandler.post(new Runnable() {
5029                    @Override
5030                    public void run() {
5031                        notifyRemoved(info, sbnLight, update, reason);
5032                    }
5033                });
5034            }
5035        }
5036
5037        /**
5038         * asynchronously notify all listeners about a reordering of notifications
5039         */
5040        public void notifyRankingUpdateLocked() {
5041            for (final ManagedServiceInfo serviceInfo : getServices()) {
5042                if (!serviceInfo.isEnabledForCurrentProfiles()) {
5043                    continue;
5044                }
5045                final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
5046                mHandler.post(new Runnable() {
5047                    @Override
5048                    public void run() {
5049                        notifyRankingUpdate(serviceInfo, update);
5050                    }
5051                });
5052            }
5053        }
5054
5055        public void notifyListenerHintsChangedLocked(final int hints) {
5056            for (final ManagedServiceInfo serviceInfo : getServices()) {
5057                if (!serviceInfo.isEnabledForCurrentProfiles()) {
5058                    continue;
5059                }
5060                mHandler.post(new Runnable() {
5061                    @Override
5062                    public void run() {
5063                        notifyListenerHintsChanged(serviceInfo, hints);
5064                    }
5065                });
5066            }
5067        }
5068
5069        public void notifyInterruptionFilterChanged(final int interruptionFilter) {
5070            for (final ManagedServiceInfo serviceInfo : getServices()) {
5071                if (!serviceInfo.isEnabledForCurrentProfiles()) {
5072                    continue;
5073                }
5074                mHandler.post(new Runnable() {
5075                    @Override
5076                    public void run() {
5077                        notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5078                    }
5079                });
5080            }
5081        }
5082
5083        protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
5084                final NotificationChannel channel, final int modificationType) {
5085            if (channel == null) {
5086                return;
5087            }
5088            for (final ManagedServiceInfo serviceInfo : getServices()) {
5089                if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5090                    continue;
5091                }
5092
5093                mHandler.post(new Runnable() {
5094                    @Override
5095                    public void run() {
5096                        if (hasCompanionDevice(serviceInfo)) {
5097                            notifyNotificationChannelChanged(
5098                                    serviceInfo, pkg, user, channel, modificationType);
5099                        }
5100                    }
5101                });
5102            }
5103        }
5104
5105        protected void notifyNotificationChannelGroupChanged(
5106                final String pkg, final UserHandle user, final NotificationChannelGroup group,
5107                final int modificationType) {
5108            if (group == null) {
5109                return;
5110            }
5111            for (final ManagedServiceInfo serviceInfo : getServices()) {
5112                if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
5113                    continue;
5114                }
5115
5116                mHandler.post(new Runnable() {
5117                    @Override
5118                    public void run() {
5119                        if (hasCompanionDevice(serviceInfo)) {
5120                            notifyNotificationChannelGroupChanged(
5121                                    serviceInfo, pkg, user, group, modificationType);
5122                        }
5123                    }
5124                });
5125            }
5126        }
5127
5128        private void notifyPosted(final ManagedServiceInfo info,
5129                final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
5130            final INotificationListener listener = (INotificationListener) info.service;
5131            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5132            try {
5133                listener.onNotificationPosted(sbnHolder, rankingUpdate);
5134            } catch (RemoteException ex) {
5135                Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5136            }
5137        }
5138
5139        private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
5140                NotificationRankingUpdate rankingUpdate, int reason) {
5141            if (!info.enabledAndUserMatches(sbn.getUserId())) {
5142                return;
5143            }
5144            final INotificationListener listener = (INotificationListener) info.service;
5145            StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5146            try {
5147                listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
5148            } catch (RemoteException ex) {
5149                Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
5150            }
5151        }
5152
5153        private void notifyRankingUpdate(ManagedServiceInfo info,
5154                                         NotificationRankingUpdate rankingUpdate) {
5155            final INotificationListener listener = (INotificationListener) info.service;
5156            try {
5157                listener.onNotificationRankingUpdate(rankingUpdate);
5158            } catch (RemoteException ex) {
5159                Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5160            }
5161        }
5162
5163        private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
5164            final INotificationListener listener = (INotificationListener) info.service;
5165            try {
5166                listener.onListenerHintsChanged(hints);
5167            } catch (RemoteException ex) {
5168                Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
5169            }
5170        }
5171
5172        private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5173                int interruptionFilter) {
5174            final INotificationListener listener = (INotificationListener) info.service;
5175            try {
5176                listener.onInterruptionFilterChanged(interruptionFilter);
5177            } catch (RemoteException ex) {
5178                Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5179            }
5180        }
5181
5182        void notifyNotificationChannelChanged(ManagedServiceInfo info,
5183                final String pkg, final UserHandle user, final NotificationChannel channel,
5184                final int modificationType) {
5185            final INotificationListener listener = (INotificationListener) info.service;
5186            try {
5187                listener.onNotificationChannelModification(pkg, user, channel, modificationType);
5188            } catch (RemoteException ex) {
5189                Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5190            }
5191        }
5192
5193        private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
5194                final String pkg, final UserHandle user, final NotificationChannelGroup group,
5195                final int modificationType) {
5196            final INotificationListener listener = (INotificationListener) info.service;
5197            try {
5198                listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
5199            } catch (RemoteException ex) {
5200                Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5201            }
5202        }
5203
5204        public boolean isListenerPackage(String packageName) {
5205            if (packageName == null) {
5206                return false;
5207            }
5208            // TODO: clean up locking object later
5209            synchronized (mNotificationLock) {
5210                for (final ManagedServiceInfo serviceInfo : getServices()) {
5211                    if (packageName.equals(serviceInfo.component.getPackageName())) {
5212                        return true;
5213                    }
5214                }
5215            }
5216            return false;
5217        }
5218    }
5219
5220    public static final class DumpFilter {
5221        public boolean filtered = false;
5222        public String pkgFilter;
5223        public boolean zen;
5224        public long since;
5225        public boolean stats;
5226        public boolean redact = true;
5227        public boolean proto = false;
5228
5229        public static DumpFilter parseFromArguments(String[] args) {
5230            final DumpFilter filter = new DumpFilter();
5231            for (int ai = 0; ai < args.length; ai++) {
5232                final String a = args[ai];
5233                if ("--proto".equals(args[0])) {
5234                    filter.proto = true;
5235                }
5236                if ("--noredact".equals(a) || "--reveal".equals(a)) {
5237                    filter.redact = false;
5238                } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5239                    if (ai < args.length-1) {
5240                        ai++;
5241                        filter.pkgFilter = args[ai].trim().toLowerCase();
5242                        if (filter.pkgFilter.isEmpty()) {
5243                            filter.pkgFilter = null;
5244                        } else {
5245                            filter.filtered = true;
5246                        }
5247                    }
5248                } else if ("--zen".equals(a) || "zen".equals(a)) {
5249                    filter.filtered = true;
5250                    filter.zen = true;
5251                } else if ("--stats".equals(a)) {
5252                    filter.stats = true;
5253                    if (ai < args.length-1) {
5254                        ai++;
5255                        filter.since = Long.parseLong(args[ai]);
5256                    } else {
5257                        filter.since = 0;
5258                    }
5259                }
5260            }
5261            return filter;
5262        }
5263
5264        public boolean matches(StatusBarNotification sbn) {
5265            if (!filtered) return true;
5266            return zen ? true : sbn != null
5267                    && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
5268        }
5269
5270        public boolean matches(ComponentName component) {
5271            if (!filtered) return true;
5272            return zen ? true : component != null && matches(component.getPackageName());
5273        }
5274
5275        public boolean matches(String pkg) {
5276            if (!filtered) return true;
5277            return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
5278        }
5279
5280        @Override
5281        public String toString() {
5282            return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
5283        }
5284    }
5285
5286    /**
5287     * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5288     * binder without sending large amounts of data over a oneway transaction.
5289     */
5290    private static final class StatusBarNotificationHolder
5291            extends IStatusBarNotificationHolder.Stub {
5292        private StatusBarNotification mValue;
5293
5294        public StatusBarNotificationHolder(StatusBarNotification value) {
5295            mValue = value;
5296        }
5297
5298        /** Get the held value and clear it. This function should only be called once per holder */
5299        @Override
5300        public StatusBarNotification get() {
5301            StatusBarNotification value = mValue;
5302            mValue = null;
5303            return value;
5304        }
5305    }
5306
5307    private final class PolicyAccess {
5308        private static final String SEPARATOR = ":";
5309        private final String[] PERM = {
5310            android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
5311        };
5312
5313        public boolean isPackageGranted(String pkg) {
5314            return pkg != null && getGrantedPackages().contains(pkg);
5315        }
5316
5317        public void put(String pkg, boolean granted) {
5318            if (pkg == null) return;
5319            final ArraySet<String> pkgs = getGrantedPackages();
5320            boolean changed;
5321            if (granted) {
5322                changed = pkgs.add(pkg);
5323            } else {
5324                changed = pkgs.remove(pkg);
5325            }
5326            if (!changed) return;
5327            final String setting = TextUtils.join(SEPARATOR, pkgs);
5328            final int currentUser = ActivityManager.getCurrentUser();
5329            Settings.Secure.putStringForUser(getContext().getContentResolver(),
5330                    Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5331                    setting,
5332                    currentUser);
5333            getContext().sendBroadcastAsUser(new Intent(NotificationManager
5334                    .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
5335                .setPackage(pkg)
5336                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
5337        }
5338
5339        public ArraySet<String> getGrantedPackages() {
5340            final ArraySet<String> pkgs = new ArraySet<>();
5341
5342            long identity = Binder.clearCallingIdentity();
5343            try {
5344                final String setting = Settings.Secure.getStringForUser(
5345                        getContext().getContentResolver(),
5346                        Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
5347                        ActivityManager.getCurrentUser());
5348                if (setting != null) {
5349                    final String[] tokens = setting.split(SEPARATOR);
5350                    for (int i = 0; i < tokens.length; i++) {
5351                        String token = tokens[i];
5352                        if (token != null) {
5353                            token = token.trim();
5354                        }
5355                        if (TextUtils.isEmpty(token)) {
5356                            continue;
5357                        }
5358                        pkgs.add(token);
5359                    }
5360                }
5361            } finally {
5362                Binder.restoreCallingIdentity(identity);
5363            }
5364            return pkgs;
5365        }
5366
5367        public String[] getRequestingPackages() throws RemoteException {
5368            final ParceledListSlice list = mPackageManager
5369                    .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
5370                            ActivityManager.getCurrentUser());
5371            final List<PackageInfo> pkgs = list.getList();
5372            if (pkgs == null || pkgs.isEmpty()) return new String[0];
5373            final int N = pkgs.size();
5374            final String[] rt = new String[N];
5375            for (int i = 0; i < N; i++) {
5376                rt[i] = pkgs.get(i).packageName;
5377            }
5378            return rt;
5379        }
5380    }
5381}
5382