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