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