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