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