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