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