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