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