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