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.app.NotificationManager.IMPORTANCE_MIN;
     20 import static android.app.NotificationManager.IMPORTANCE_NONE;
     21 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
     22 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
     23 import static android.service.notification.NotificationListenerService
     24         .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
     25 import static android.service.notification.NotificationListenerService
     26         .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
     27 import static android.service.notification.NotificationListenerService
     28         .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
     29 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
     30 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
     31 import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
     32 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
     33 import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
     34 import static android.service.notification.NotificationListenerService.REASON_CLICK;
     35 import static android.service.notification.NotificationListenerService.REASON_ERROR;
     36 import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
     37 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
     38 import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
     39 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
     40 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
     41 import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
     42 import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
     43 import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
     44 import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
     45 import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
     46 import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
     47 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
     48 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
     49 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
     50 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
     51 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
     52 import static android.service.notification.NotificationListenerService.TRIM_FULL;
     53 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
     54 
     55 import static android.view.Display.DEFAULT_DISPLAY;
     56 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
     57 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
     58 
     59 import android.Manifest;
     60 import android.annotation.NonNull;
     61 import android.annotation.Nullable;
     62 import android.app.ActivityManager;
     63 import android.app.ActivityManagerInternal;
     64 import android.app.AlarmManager;
     65 import android.app.AppGlobals;
     66 import android.app.AppOpsManager;
     67 import android.app.AutomaticZenRule;
     68 import android.app.NotificationChannelGroup;
     69 import android.app.backup.BackupManager;
     70 import android.app.IActivityManager;
     71 import android.app.INotificationManager;
     72 import android.app.ITransientNotification;
     73 import android.app.Notification;
     74 import android.app.NotificationChannel;
     75 import android.app.NotificationManager.Policy;
     76 import android.app.NotificationManager;
     77 import android.app.PendingIntent;
     78 import android.app.StatusBarManager;
     79 import android.app.usage.UsageEvents;
     80 import android.app.usage.UsageStatsManagerInternal;
     81 import android.companion.ICompanionDeviceManager;
     82 import android.content.BroadcastReceiver;
     83 import android.content.ComponentName;
     84 import android.content.ContentResolver;
     85 import android.content.Context;
     86 import android.content.Intent;
     87 import android.content.IntentFilter;
     88 import android.content.pm.ApplicationInfo;
     89 import android.content.pm.IPackageManager;
     90 import android.content.pm.PackageInfo;
     91 import android.content.pm.PackageManager;
     92 import android.content.pm.PackageManager.NameNotFoundException;
     93 import android.content.pm.ParceledListSlice;
     94 import android.content.res.Resources;
     95 import android.database.ContentObserver;
     96 import android.media.AudioManager;
     97 import android.media.AudioManagerInternal;
     98 import android.media.IRingtonePlayer;
     99 import android.media.ToneGenerator;
    100 import android.net.Uri;
    101 import android.os.Binder;
    102 import android.os.Build;
    103 import android.os.Bundle;
    104 import android.os.Environment;
    105 import android.os.Handler;
    106 import android.os.HandlerThread;
    107 import android.os.IBinder;
    108 import android.os.IInterface;
    109 import android.os.Looper;
    110 import android.os.Message;
    111 import android.os.Process;
    112 import android.os.RemoteException;
    113 import android.os.ServiceManager;
    114 import android.os.SystemClock;
    115 import android.os.SystemProperties;
    116 import android.os.UserHandle;
    117 import android.os.Vibrator;
    118 import android.os.VibrationEffect;
    119 import android.provider.Settings;
    120 import android.service.notification.Adjustment;
    121 import android.service.notification.Condition;
    122 import android.service.notification.IConditionProvider;
    123 import android.service.notification.INotificationListener;
    124 import android.service.notification.IStatusBarNotificationHolder;
    125 import android.service.notification.NotificationAssistantService;
    126 import android.service.notification.NotificationListenerService;
    127 import android.service.notification.NotificationRankingUpdate;
    128 import android.service.notification.NotificationRecordProto;
    129 import android.service.notification.NotificationServiceDumpProto;
    130 import android.service.notification.NotificationServiceProto;
    131 import android.service.notification.SnoozeCriterion;
    132 import android.service.notification.StatusBarNotification;
    133 import android.service.notification.ZenModeConfig;
    134 import android.service.notification.ZenModeProto;
    135 import android.telephony.PhoneStateListener;
    136 import android.telephony.TelephonyManager;
    137 import android.text.TextUtils;
    138 import android.util.ArrayMap;
    139 import android.util.ArraySet;
    140 import android.util.AtomicFile;
    141 import android.util.Log;
    142 import android.util.Slog;
    143 import android.util.SparseArray;
    144 import android.util.Xml;
    145 import android.util.proto.ProtoOutputStream;
    146 import android.view.WindowManagerInternal;
    147 import android.view.accessibility.AccessibilityEvent;
    148 import android.view.accessibility.AccessibilityManager;
    149 import android.widget.Toast;
    150 
    151 import com.android.internal.R;
    152 import com.android.internal.annotations.GuardedBy;
    153 import com.android.internal.annotations.VisibleForTesting;
    154 import com.android.internal.logging.MetricsLogger;
    155 import com.android.internal.logging.nano.MetricsProto;
    156 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
    157 import com.android.internal.statusbar.NotificationVisibility;
    158 import com.android.internal.util.ArrayUtils;
    159 import com.android.internal.util.DumpUtils;
    160 import com.android.internal.util.FastXmlSerializer;
    161 import com.android.internal.util.Preconditions;
    162 import com.android.server.DeviceIdleController;
    163 import com.android.server.EventLogTags;
    164 import com.android.server.LocalServices;
    165 import com.android.server.SystemService;
    166 import com.android.server.lights.Light;
    167 import com.android.server.lights.LightsManager;
    168 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
    169 import com.android.server.policy.PhoneWindowManager;
    170 import com.android.server.statusbar.StatusBarManagerInternal;
    171 import com.android.server.notification.ManagedServices.UserProfiles;
    172 
    173 import libcore.io.IoUtils;
    174 
    175 import org.json.JSONException;
    176 import org.json.JSONObject;
    177 import org.xmlpull.v1.XmlPullParser;
    178 import org.xmlpull.v1.XmlPullParserException;
    179 import org.xmlpull.v1.XmlSerializer;
    180 
    181 import java.io.ByteArrayInputStream;
    182 import java.io.ByteArrayOutputStream;
    183 import java.io.File;
    184 import java.io.FileDescriptor;
    185 import java.io.FileInputStream;
    186 import java.io.FileNotFoundException;
    187 import java.io.FileOutputStream;
    188 import java.io.IOException;
    189 import java.io.InputStream;
    190 import java.io.OutputStream;
    191 import java.io.PrintWriter;
    192 import java.nio.charset.StandardCharsets;
    193 import java.util.ArrayDeque;
    194 import java.util.ArrayList;
    195 import java.util.Arrays;
    196 import java.util.Iterator;
    197 import java.util.List;
    198 import java.util.Map;
    199 import java.util.Map.Entry;
    200 import java.util.Objects;
    201 import java.util.concurrent.TimeUnit;
    202 
    203 /** {@hide} */
    204 public class NotificationManagerService extends SystemService {
    205     static final String TAG = "NotificationService";
    206     static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
    207     public static final boolean ENABLE_CHILD_NOTIFICATIONS
    208             = SystemProperties.getBoolean("debug.child_notifs", true);
    209 
    210     static final int MAX_PACKAGE_NOTIFICATIONS = 50;
    211     static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f;
    212 
    213     // message codes
    214     static final int MESSAGE_TIMEOUT = 2;
    215     static final int MESSAGE_SAVE_POLICY_FILE = 3;
    216     static final int MESSAGE_SEND_RANKING_UPDATE = 4;
    217     static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
    218     static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
    219 
    220     // ranking thread messages
    221     private static final int MESSAGE_RECONSIDER_RANKING = 1000;
    222     private static final int MESSAGE_RANKING_SORT = 1001;
    223 
    224     static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
    225     static final int SHORT_DELAY = 2000; // 2 seconds
    226 
    227     static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
    228 
    229     static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
    230 
    231     static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
    232 
    233     static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
    234 
    235     static final boolean ENABLE_BLOCKED_TOASTS = true;
    236 
    237     // When #matchesCallFilter is called from the ringer, wait at most
    238     // 3s to resolve the contacts. This timeout is required since
    239     // ContactsProvider might take a long time to start up.
    240     //
    241     // Return STARRED_CONTACT when the timeout is hit in order to avoid
    242     // missed calls in ZEN mode "Important".
    243     static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
    244     static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
    245             ValidateNotificationPeople.STARRED_CONTACT;
    246 
    247     /** notification_enqueue status value for a newly enqueued notification. */
    248     private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
    249 
    250     /** notification_enqueue status value for an existing notification. */
    251     private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
    252 
    253     /** notification_enqueue status value for an ignored notification. */
    254     private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
    255     private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
    256 
    257     private static final long DELAY_FOR_ASSISTANT_TIME = 100;
    258 
    259     private static final String ACTION_NOTIFICATION_TIMEOUT =
    260             NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
    261     private static final int REQUEST_CODE_TIMEOUT = 1;
    262     private static final String SCHEME_TIMEOUT = "timeout";
    263     private static final String EXTRA_KEY = "key";
    264 
    265     private IActivityManager mAm;
    266     private IPackageManager mPackageManager;
    267     private PackageManager mPackageManagerClient;
    268     AudioManager mAudioManager;
    269     AudioManagerInternal mAudioManagerInternal;
    270     @Nullable StatusBarManagerInternal mStatusBar;
    271     Vibrator mVibrator;
    272     private WindowManagerInternal mWindowManagerInternal;
    273     private AlarmManager mAlarmManager;
    274     private ICompanionDeviceManager mCompanionManager;
    275 
    276     final IBinder mForegroundToken = new Binder();
    277     private Handler mHandler;
    278     private final HandlerThread mRankingThread = new HandlerThread("ranker",
    279             Process.THREAD_PRIORITY_BACKGROUND);
    280 
    281     private Light mNotificationLight;
    282     Light mAttentionLight;
    283 
    284     private long[] mFallbackVibrationPattern;
    285     private boolean mUseAttentionLight;
    286     boolean mSystemReady;
    287 
    288     private boolean mDisableNotificationEffects;
    289     private int mCallState;
    290     private String mSoundNotificationKey;
    291     private String mVibrateNotificationKey;
    292 
    293     private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
    294             new SparseArray<ArraySet<ManagedServiceInfo>>();
    295     private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
    296     private int mListenerHints;  // right now, all hints are global
    297     private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
    298 
    299     // for enabling and disabling notification pulse behavior
    300     private boolean mScreenOn = true;
    301     private boolean mInCall = false;
    302     private boolean mNotificationPulseEnabled;
    303 
    304     // for generating notification tones in-call
    305     private ToneGenerator mInCallToneGenerator;
    306     private final Object mInCallToneGeneratorLock = new Object();
    307 
    308     // used as a mutex for access to all active notifications & listeners
    309     final Object mNotificationLock = new Object();
    310     @GuardedBy("mNotificationLock")
    311     final ArrayList<NotificationRecord> mNotificationList =
    312             new ArrayList<NotificationRecord>();
    313     @GuardedBy("mNotificationLock")
    314     final ArrayMap<String, NotificationRecord> mNotificationsByKey =
    315             new ArrayMap<String, NotificationRecord>();
    316     @GuardedBy("mNotificationLock")
    317     final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
    318     @GuardedBy("mNotificationLock")
    319     final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
    320     final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
    321     final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
    322     final PolicyAccess mPolicyAccess = new PolicyAccess();
    323 
    324     // The last key in this list owns the hardware.
    325     ArrayList<String> mLights = new ArrayList<>();
    326 
    327     private AppOpsManager mAppOps;
    328     private UsageStatsManagerInternal mAppUsageStats;
    329 
    330     private Archive mArchive;
    331 
    332     // Persistent storage for notification policy
    333     private AtomicFile mPolicyFile;
    334 
    335     private static final int DB_VERSION = 1;
    336 
    337     private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
    338     private static final String ATTR_VERSION = "version";
    339 
    340     private RankingHelper mRankingHelper;
    341 
    342     private final UserProfiles mUserProfiles = new UserProfiles();
    343     private NotificationListeners mListeners;
    344     private NotificationAssistants mNotificationAssistants;
    345     private ConditionProviders mConditionProviders;
    346     private NotificationUsageStats mUsageStats;
    347 
    348     private static final int MY_UID = Process.myUid();
    349     private static final int MY_PID = Process.myPid();
    350     private static final IBinder WHITELIST_TOKEN = new Binder();
    351     private RankingHandler mRankingHandler;
    352     private long mLastOverRateLogTime;
    353     private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
    354 
    355     private SnoozeHelper mSnoozeHelper;
    356     private GroupHelper mGroupHelper;
    357     private boolean mIsTelevision;
    358 
    359     private static class Archive {
    360         final int mBufferSize;
    361         final ArrayDeque<StatusBarNotification> mBuffer;
    362 
    363         public Archive(int size) {
    364             mBufferSize = size;
    365             mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
    366         }
    367 
    368         public String toString() {
    369             final StringBuilder sb = new StringBuilder();
    370             final int N = mBuffer.size();
    371             sb.append("Archive (");
    372             sb.append(N);
    373             sb.append(" notification");
    374             sb.append((N==1)?")":"s)");
    375             return sb.toString();
    376         }
    377 
    378         public void record(StatusBarNotification nr) {
    379             if (mBuffer.size() == mBufferSize) {
    380                 mBuffer.removeFirst();
    381             }
    382 
    383             // We don't want to store the heavy bits of the notification in the archive,
    384             // but other clients in the system process might be using the object, so we
    385             // store a (lightened) copy.
    386             mBuffer.addLast(nr.cloneLight());
    387         }
    388 
    389         public Iterator<StatusBarNotification> descendingIterator() {
    390             return mBuffer.descendingIterator();
    391         }
    392 
    393         public StatusBarNotification[] getArray(int count) {
    394             if (count == 0) count = mBufferSize;
    395             final StatusBarNotification[] a
    396                     = new StatusBarNotification[Math.min(count, mBuffer.size())];
    397             Iterator<StatusBarNotification> iter = descendingIterator();
    398             int i=0;
    399             while (iter.hasNext() && i < count) {
    400                 a[i++] = iter.next();
    401             }
    402             return a;
    403         }
    404 
    405     }
    406 
    407     private void readPolicyXml(InputStream stream, boolean forRestore)
    408             throws XmlPullParserException, NumberFormatException, IOException {
    409         final XmlPullParser parser = Xml.newPullParser();
    410         parser.setInput(stream, StandardCharsets.UTF_8.name());
    411 
    412         while (parser.next() != END_DOCUMENT) {
    413             mZenModeHelper.readXml(parser, forRestore);
    414             mRankingHelper.readXml(parser, forRestore);
    415         }
    416     }
    417 
    418     private void loadPolicyFile() {
    419         if (DBG) Slog.d(TAG, "loadPolicyFile");
    420         synchronized (mPolicyFile) {
    421 
    422             FileInputStream infile = null;
    423             try {
    424                 infile = mPolicyFile.openRead();
    425                 readPolicyXml(infile, false /*forRestore*/);
    426             } catch (FileNotFoundException e) {
    427                 // No data yet
    428             } catch (IOException e) {
    429                 Log.wtf(TAG, "Unable to read notification policy", e);
    430             } catch (NumberFormatException e) {
    431                 Log.wtf(TAG, "Unable to parse notification policy", e);
    432             } catch (XmlPullParserException e) {
    433                 Log.wtf(TAG, "Unable to parse notification policy", e);
    434             } finally {
    435                 IoUtils.closeQuietly(infile);
    436             }
    437         }
    438     }
    439 
    440     public void savePolicyFile() {
    441         mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
    442         mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
    443     }
    444 
    445     private void handleSavePolicyFile() {
    446         if (DBG) Slog.d(TAG, "handleSavePolicyFile");
    447         synchronized (mPolicyFile) {
    448             final FileOutputStream stream;
    449             try {
    450                 stream = mPolicyFile.startWrite();
    451             } catch (IOException e) {
    452                 Slog.w(TAG, "Failed to save policy file", e);
    453                 return;
    454             }
    455 
    456             try {
    457                 writePolicyXml(stream, false /*forBackup*/);
    458                 mPolicyFile.finishWrite(stream);
    459             } catch (IOException e) {
    460                 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
    461                 mPolicyFile.failWrite(stream);
    462             }
    463         }
    464         BackupManager.dataChanged(getContext().getPackageName());
    465     }
    466 
    467     private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
    468         final XmlSerializer out = new FastXmlSerializer();
    469         out.setOutput(stream, StandardCharsets.UTF_8.name());
    470         out.startDocument(null, true);
    471         out.startTag(null, TAG_NOTIFICATION_POLICY);
    472         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
    473         mZenModeHelper.writeXml(out, forBackup);
    474         mRankingHelper.writeXml(out, forBackup);
    475         out.endTag(null, TAG_NOTIFICATION_POLICY);
    476         out.endDocument();
    477     }
    478 
    479     /** Use this to check if a package can post a notification or toast. */
    480     private boolean checkNotificationOp(String pkg, int uid) {
    481         return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
    482                 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
    483     }
    484 
    485     private static final class ToastRecord
    486     {
    487         final int pid;
    488         final String pkg;
    489         final ITransientNotification callback;
    490         int duration;
    491         Binder token;
    492 
    493         ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
    494                     Binder token) {
    495             this.pid = pid;
    496             this.pkg = pkg;
    497             this.callback = callback;
    498             this.duration = duration;
    499             this.token = token;
    500         }
    501 
    502         void update(int duration) {
    503             this.duration = duration;
    504         }
    505 
    506         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
    507             if (filter != null && !filter.matches(pkg)) return;
    508             pw.println(prefix + this);
    509         }
    510 
    511         @Override
    512         public final String toString()
    513         {
    514             return "ToastRecord{"
    515                 + Integer.toHexString(System.identityHashCode(this))
    516                 + " pkg=" + pkg
    517                 + " callback=" + callback
    518                 + " duration=" + duration;
    519         }
    520     }
    521 
    522     private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
    523 
    524         @Override
    525         public void onSetDisabled(int status) {
    526             synchronized (mNotificationLock) {
    527                 mDisableNotificationEffects =
    528                         (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
    529                 if (disableNotificationEffects(null) != null) {
    530                     // cancel whatever's going on
    531                     long identity = Binder.clearCallingIdentity();
    532                     try {
    533                         final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
    534                         if (player != null) {
    535                             player.stopAsync();
    536                         }
    537                     } catch (RemoteException e) {
    538                     } finally {
    539                         Binder.restoreCallingIdentity(identity);
    540                     }
    541 
    542                     identity = Binder.clearCallingIdentity();
    543                     try {
    544                         mVibrator.cancel();
    545                     } finally {
    546                         Binder.restoreCallingIdentity(identity);
    547                     }
    548                 }
    549             }
    550         }
    551 
    552         @Override
    553         public void onClearAll(int callingUid, int callingPid, int userId) {
    554             synchronized (mNotificationLock) {
    555                 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
    556                         /*includeCurrentProfiles*/ true);
    557             }
    558         }
    559 
    560         @Override
    561         public void onNotificationClick(int callingUid, int callingPid, String key) {
    562             synchronized (mNotificationLock) {
    563                 NotificationRecord r = mNotificationsByKey.get(key);
    564                 if (r == null) {
    565                     Log.w(TAG, "No notification with key: " + key);
    566                     return;
    567                 }
    568                 final long now = System.currentTimeMillis();
    569                 MetricsLogger.action(r.getLogMaker(now)
    570                         .setCategory(MetricsEvent.NOTIFICATION_ITEM)
    571                         .setType(MetricsEvent.TYPE_ACTION));
    572                 EventLogTags.writeNotificationClicked(key,
    573                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
    574 
    575                 StatusBarNotification sbn = r.sbn;
    576                 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
    577                         sbn.getId(), Notification.FLAG_AUTO_CANCEL,
    578                         Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
    579                         REASON_CLICK, null);
    580             }
    581         }
    582 
    583         @Override
    584         public void onNotificationActionClick(int callingUid, int callingPid, String key,
    585                 int actionIndex) {
    586             synchronized (mNotificationLock) {
    587                 NotificationRecord r = mNotificationsByKey.get(key);
    588                 if (r == null) {
    589                     Log.w(TAG, "No notification with key: " + key);
    590                     return;
    591                 }
    592                 final long now = System.currentTimeMillis();
    593                 MetricsLogger.action(r.getLogMaker(now)
    594                         .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
    595                         .setType(MetricsEvent.TYPE_ACTION)
    596                         .setSubtype(actionIndex));
    597                 EventLogTags.writeNotificationActionClicked(key, actionIndex,
    598                         r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
    599                 // TODO: Log action click via UsageStats.
    600             }
    601         }
    602 
    603         @Override
    604         public void onNotificationClear(int callingUid, int callingPid,
    605                 String pkg, String tag, int id, int userId) {
    606             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
    607                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
    608                     true, userId, REASON_CANCEL, null);
    609         }
    610 
    611         @Override
    612         public void onPanelRevealed(boolean clearEffects, int items) {
    613             MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
    614             MetricsLogger.histogram(getContext(), "note_load", items);
    615             EventLogTags.writeNotificationPanelRevealed(items);
    616             if (clearEffects) {
    617                 clearEffects();
    618             }
    619         }
    620 
    621         @Override
    622         public void onPanelHidden() {
    623             MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
    624             EventLogTags.writeNotificationPanelHidden();
    625         }
    626 
    627         @Override
    628         public void clearEffects() {
    629             synchronized (mNotificationLock) {
    630                 if (DBG) Slog.d(TAG, "clearEffects");
    631                 clearSoundLocked();
    632                 clearVibrateLocked();
    633                 clearLightsLocked();
    634             }
    635         }
    636 
    637         @Override
    638         public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
    639                 int uid, int initialPid, String message, int userId) {
    640             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
    641                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
    642             cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
    643                     REASON_ERROR, null);
    644             long ident = Binder.clearCallingIdentity();
    645             try {
    646                 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
    647                         "Bad notification posted from package " + pkg
    648                         + ": " + message);
    649             } catch (RemoteException e) {
    650             }
    651             Binder.restoreCallingIdentity(ident);
    652         }
    653 
    654         @Override
    655         public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
    656                 NotificationVisibility[] noLongerVisibleKeys) {
    657             synchronized (mNotificationLock) {
    658                 for (NotificationVisibility nv : newlyVisibleKeys) {
    659                     NotificationRecord r = mNotificationsByKey.get(nv.key);
    660                     if (r == null) continue;
    661                     r.setVisibility(true, nv.rank);
    662                     nv.recycle();
    663                 }
    664                 // Note that we might receive this event after notifications
    665                 // have already left the system, e.g. after dismissing from the
    666                 // shade. Hence not finding notifications in
    667                 // mNotificationsByKey is not an exceptional condition.
    668                 for (NotificationVisibility nv : noLongerVisibleKeys) {
    669                     NotificationRecord r = mNotificationsByKey.get(nv.key);
    670                     if (r == null) continue;
    671                     r.setVisibility(false, nv.rank);
    672                     nv.recycle();
    673                 }
    674             }
    675         }
    676 
    677         @Override
    678         public void onNotificationExpansionChanged(String key,
    679                 boolean userAction, boolean expanded) {
    680             synchronized (mNotificationLock) {
    681                 NotificationRecord r = mNotificationsByKey.get(key);
    682                 if (r != null) {
    683                     r.stats.onExpansionChanged(userAction, expanded);
    684                     final long now = System.currentTimeMillis();
    685                     MetricsLogger.action(r.getLogMaker(now)
    686                             .setCategory(MetricsEvent.NOTIFICATION_ITEM)
    687                             .setType(MetricsEvent.TYPE_DETAIL));
    688                     EventLogTags.writeNotificationExpansion(key,
    689                             userAction ? 1 : 0, expanded ? 1 : 0,
    690                             r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
    691                 }
    692             }
    693         }
    694     };
    695 
    696     @GuardedBy("mNotificationLock")
    697     private void clearSoundLocked() {
    698         mSoundNotificationKey = null;
    699         long identity = Binder.clearCallingIdentity();
    700         try {
    701             final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
    702             if (player != null) {
    703                 player.stopAsync();
    704             }
    705         } catch (RemoteException e) {
    706         } finally {
    707             Binder.restoreCallingIdentity(identity);
    708         }
    709     }
    710 
    711     @GuardedBy("mNotificationLock")
    712     private void clearVibrateLocked() {
    713         mVibrateNotificationKey = null;
    714         long identity = Binder.clearCallingIdentity();
    715         try {
    716             mVibrator.cancel();
    717         } finally {
    718             Binder.restoreCallingIdentity(identity);
    719         }
    720     }
    721 
    722     @GuardedBy("mNotificationLock")
    723     private void clearLightsLocked() {
    724         // light
    725         mLights.clear();
    726         updateLightsLocked();
    727     }
    728 
    729     private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
    730         @Override
    731         public void onReceive(Context context, Intent intent) {
    732             String action = intent.getAction();
    733             if (action == null) {
    734                 return;
    735             }
    736             if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
    737                 final NotificationRecord record;
    738                 synchronized (mNotificationLock) {
    739                     record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
    740                 }
    741                 if (record != null) {
    742                     cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
    743                             record.sbn.getPackageName(), record.sbn.getTag(),
    744                             record.sbn.getId(), 0,
    745                             Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
    746                             REASON_TIMEOUT, null);
    747                 }
    748             }
    749         }
    750     };
    751 
    752     private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
    753         @Override
    754         public void onReceive(Context context, Intent intent) {
    755             String action = intent.getAction();
    756             if (action == null) {
    757                 return;
    758             }
    759 
    760             boolean queryRestart = false;
    761             boolean queryRemove = false;
    762             boolean packageChanged = false;
    763             boolean cancelNotifications = true;
    764             int reason = REASON_PACKAGE_CHANGED;
    765 
    766             if (action.equals(Intent.ACTION_PACKAGE_ADDED)
    767                     || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
    768                     || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
    769                     || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
    770                     || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
    771                     || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
    772                     || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
    773                 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
    774                         UserHandle.USER_ALL);
    775                 String pkgList[] = null;
    776                 int uidList[] = null;
    777                 boolean removingPackage = queryRemove &&
    778                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
    779                 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
    780                 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
    781                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    782                     uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
    783                 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
    784                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    785                     reason = REASON_PACKAGE_SUSPENDED;
    786                 } else if (queryRestart) {
    787                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
    788                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
    789                 } else {
    790                     Uri uri = intent.getData();
    791                     if (uri == null) {
    792                         return;
    793                     }
    794                     String pkgName = uri.getSchemeSpecificPart();
    795                     if (pkgName == null) {
    796                         return;
    797                     }
    798                     if (packageChanged) {
    799                         // We cancel notifications for packages which have just been disabled
    800                         try {
    801                             final int enabled = mPackageManager.getApplicationEnabledSetting(
    802                                     pkgName,
    803                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
    804                                             UserHandle.USER_SYSTEM);
    805                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
    806                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
    807                                 cancelNotifications = false;
    808                             }
    809                         } catch (IllegalArgumentException e) {
    810                             // Package doesn't exist; probably racing with uninstall.
    811                             // cancelNotifications is already true, so nothing to do here.
    812                             if (DBG) {
    813                                 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
    814                             }
    815                         } catch (RemoteException e) {
    816                             // Failed to talk to PackageManagerService Should never happen!
    817                         }
    818                     }
    819                     pkgList = new String[]{pkgName};
    820                     uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
    821                 }
    822                 if (pkgList != null && (pkgList.length > 0)) {
    823                     for (String pkgName : pkgList) {
    824                         if (cancelNotifications) {
    825                             cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
    826                                     !queryRestart, changeUserId, reason, null);
    827                         }
    828                     }
    829                 }
    830                 mListeners.onPackagesChanged(removingPackage, pkgList);
    831                 mNotificationAssistants.onPackagesChanged(removingPackage, pkgList);
    832                 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
    833                 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
    834                 savePolicyFile();
    835             }
    836         }
    837     };
    838 
    839     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
    840         @Override
    841         public void onReceive(Context context, Intent intent) {
    842             String action = intent.getAction();
    843 
    844             if (action.equals(Intent.ACTION_SCREEN_ON)) {
    845                 // Keep track of screen on/off state, but do not turn off the notification light
    846                 // until user passes through the lock screen or views the notification.
    847                 mScreenOn = true;
    848                 updateNotificationPulse();
    849             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    850                 mScreenOn = false;
    851                 updateNotificationPulse();
    852             } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
    853                 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
    854                         .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
    855                 updateNotificationPulse();
    856                 synchronized (mInCallToneGeneratorLock) {
    857                     if (mInCall) {
    858                         if (mInCallToneGenerator == null) {
    859                             int relativeToneVolume = getContext().getResources().getInteger(
    860                                     R.integer.config_inCallNotificationVolumeRelative);
    861                             if (relativeToneVolume < ToneGenerator.MIN_VOLUME
    862                                     || relativeToneVolume > ToneGenerator.MAX_VOLUME) {
    863                                 relativeToneVolume = ToneGenerator.MAX_VOLUME;
    864                             }
    865                             try {
    866                                 mInCallToneGenerator = new ToneGenerator(
    867                                         AudioManager.STREAM_VOICE_CALL, relativeToneVolume);
    868                             } catch (RuntimeException e) {
    869                                 Log.e(TAG, "Error creating local tone generator: " + e);
    870                                 mInCallToneGenerator = null;
    871                             }
    872                         }
    873                     } else {
    874                         if (mInCallToneGenerator != null) {
    875                             mInCallToneGenerator.release();
    876                             mInCallToneGenerator = null;
    877                         }
    878                      }
    879                 }
    880             } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
    881                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
    882                 if (userHandle >= 0) {
    883                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
    884                             REASON_USER_STOPPED, null);
    885                 }
    886             } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
    887                 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
    888                 if (userHandle >= 0) {
    889                     cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
    890                             REASON_PROFILE_TURNED_OFF, null);
    891                 }
    892             } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
    893                 // turn off LED when user passes through lock screen
    894                 mNotificationLight.turnOff();
    895             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
    896                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
    897                 // reload per-user settings
    898                 mSettingsObserver.update(null);
    899                 mUserProfiles.updateCache(context);
    900                 // Refresh managed services
    901                 mConditionProviders.onUserSwitched(user);
    902                 mListeners.onUserSwitched(user);
    903                 mNotificationAssistants.onUserSwitched(user);
    904                 mZenModeHelper.onUserSwitched(user);
    905             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
    906                 mUserProfiles.updateCache(context);
    907             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
    908                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
    909                 mZenModeHelper.onUserRemoved(user);
    910                 mRankingHelper.onUserRemoved(user);
    911                 savePolicyFile();
    912             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
    913                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
    914                 mConditionProviders.onUserUnlocked(user);
    915                 mListeners.onUserUnlocked(user);
    916                 mNotificationAssistants.onUserUnlocked(user);
    917                 mZenModeHelper.onUserUnlocked(user);
    918             }
    919         }
    920     };
    921 
    922     private final class SettingsObserver extends ContentObserver {
    923         private final Uri NOTIFICATION_BADGING_URI
    924                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
    925         private final Uri NOTIFICATION_LIGHT_PULSE_URI
    926                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
    927         private final Uri NOTIFICATION_RATE_LIMIT_URI
    928                 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
    929 
    930         SettingsObserver(Handler handler) {
    931             super(handler);
    932         }
    933 
    934         void observe() {
    935             ContentResolver resolver = getContext().getContentResolver();
    936             resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
    937                     false, this, UserHandle.USER_ALL);
    938             resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
    939                     false, this, UserHandle.USER_ALL);
    940             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
    941                     false, this, UserHandle.USER_ALL);
    942             update(null);
    943         }
    944 
    945         @Override public void onChange(boolean selfChange, Uri uri) {
    946             update(uri);
    947         }
    948 
    949         public void update(Uri uri) {
    950             ContentResolver resolver = getContext().getContentResolver();
    951             if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
    952                 boolean pulseEnabled = Settings.System.getInt(resolver,
    953                             Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
    954                 if (mNotificationPulseEnabled != pulseEnabled) {
    955                     mNotificationPulseEnabled = pulseEnabled;
    956                     updateNotificationPulse();
    957                 }
    958             }
    959             if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
    960                 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
    961                             Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
    962             }
    963             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
    964                 mRankingHelper.updateBadgingEnabled();
    965             }
    966         }
    967     }
    968 
    969     private SettingsObserver mSettingsObserver;
    970     private ZenModeHelper mZenModeHelper;
    971 
    972     static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
    973         int[] ar = r.getIntArray(resid);
    974         if (ar == null) {
    975             return def;
    976         }
    977         final int len = ar.length > maxlen ? maxlen : ar.length;
    978         long[] out = new long[len];
    979         for (int i=0; i<len; i++) {
    980             out[i] = ar[i];
    981         }
    982         return out;
    983     }
    984 
    985     public NotificationManagerService(Context context) {
    986         super(context);
    987         Notification.processWhitelistToken = WHITELIST_TOKEN;
    988     }
    989 
    990     // TODO - replace these methods with a single VisibleForTesting constructor
    991     @VisibleForTesting
    992     void setAudioManager(AudioManager audioMananger) {
    993         mAudioManager = audioMananger;
    994     }
    995 
    996     @VisibleForTesting
    997     void setVibrator(Vibrator vibrator) {
    998         mVibrator = vibrator;
    999     }
   1000 
   1001     @VisibleForTesting
   1002     void setLights(Light light) {
   1003         mNotificationLight = light;
   1004         mAttentionLight = light;
   1005         mNotificationPulseEnabled = true;
   1006     }
   1007 
   1008     @VisibleForTesting
   1009     void setScreenOn(boolean on) {
   1010         mScreenOn = on;
   1011     }
   1012 
   1013     @VisibleForTesting
   1014     void addNotification(NotificationRecord r) {
   1015         mNotificationList.add(r);
   1016         mNotificationsByKey.put(r.sbn.getKey(), r);
   1017         if (r.sbn.isGroup()) {
   1018             mSummaryByGroupKey.put(r.getGroupKey(), r);
   1019         }
   1020     }
   1021 
   1022     @VisibleForTesting
   1023     void addEnqueuedNotification(NotificationRecord r) {
   1024         mEnqueuedNotifications.add(r);
   1025     }
   1026 
   1027     @VisibleForTesting
   1028     void setSystemReady(boolean systemReady) {
   1029         mSystemReady = systemReady;
   1030     }
   1031 
   1032     @VisibleForTesting
   1033     void setHandler(Handler handler) {
   1034         mHandler = handler;
   1035     }
   1036 
   1037     @VisibleForTesting
   1038     void setFallbackVibrationPattern(long[] vibrationPattern) {
   1039         mFallbackVibrationPattern = vibrationPattern;
   1040     }
   1041 
   1042     @VisibleForTesting
   1043     void setPackageManager(IPackageManager packageManager) {
   1044         mPackageManager = packageManager;
   1045     }
   1046 
   1047     @VisibleForTesting
   1048     void setRankingHelper(RankingHelper rankingHelper) {
   1049         mRankingHelper = rankingHelper;
   1050     }
   1051 
   1052     @VisibleForTesting
   1053     void setIsTelevision(boolean isTelevision) {
   1054         mIsTelevision = isTelevision;
   1055     }
   1056 
   1057     // TODO: Tests should call onStart instead once the methods above are removed.
   1058     @VisibleForTesting
   1059     void init(Looper looper, IPackageManager packageManager, PackageManager packageManagerClient,
   1060             LightsManager lightsManager, NotificationListeners notificationListeners,
   1061             ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
   1062             NotificationUsageStats usageStats) {
   1063         Resources resources = getContext().getResources();
   1064         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
   1065                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
   1066                 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
   1067 
   1068         mAm = ActivityManager.getService();
   1069         mPackageManager = packageManager;
   1070         mPackageManagerClient = packageManagerClient;
   1071         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
   1072         mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
   1073         mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
   1074         mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
   1075         mCompanionManager = companionManager;
   1076 
   1077         mHandler = new WorkerHandler(looper);
   1078         mRankingThread.start();
   1079         String[] extractorNames;
   1080         try {
   1081             extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
   1082         } catch (Resources.NotFoundException e) {
   1083             extractorNames = new String[0];
   1084         }
   1085         mUsageStats = usageStats;
   1086         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
   1087         mRankingHelper = new RankingHelper(getContext(),
   1088                 getContext().getPackageManager(),
   1089                 mRankingHandler,
   1090                 mUsageStats,
   1091                 extractorNames);
   1092         mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
   1093         mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
   1094         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
   1095             @Override
   1096             public void onConfigChanged() {
   1097                 savePolicyFile();
   1098             }
   1099 
   1100             @Override
   1101             void onZenModeChanged() {
   1102                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
   1103                 getContext().sendBroadcastAsUser(
   1104                         new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
   1105                                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
   1106                         UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
   1107                 synchronized (mNotificationLock) {
   1108                     updateInterruptionFilterLocked();
   1109                 }
   1110             }
   1111 
   1112             @Override
   1113             void onPolicyChanged() {
   1114                 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
   1115             }
   1116         });
   1117         mSnoozeHelper = snoozeHelper;
   1118         mGroupHelper = new GroupHelper(new GroupHelper.Callback() {
   1119             @Override
   1120             public void addAutoGroup(String key) {
   1121                 synchronized (mNotificationLock) {
   1122                     addAutogroupKeyLocked(key);
   1123                 }
   1124                 mRankingHandler.requestSort(false);
   1125             }
   1126 
   1127             @Override
   1128             public void removeAutoGroup(String key) {
   1129                 synchronized (mNotificationLock) {
   1130                     removeAutogroupKeyLocked(key);
   1131                 }
   1132                 mRankingHandler.requestSort(false);
   1133             }
   1134 
   1135             @Override
   1136             public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
   1137                 createAutoGroupSummary(userId, pkg, triggeringKey);
   1138             }
   1139 
   1140             @Override
   1141             public void removeAutoGroupSummary(int userId, String pkg) {
   1142                 synchronized (mNotificationLock) {
   1143                     clearAutogroupSummaryLocked(userId, pkg);
   1144                 }
   1145             }
   1146         });
   1147 
   1148         final File systemDir = new File(Environment.getDataDirectory(), "system");
   1149         mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
   1150 
   1151         loadPolicyFile();
   1152 
   1153         // This is a ManagedServices object that keeps track of the listeners.
   1154         mListeners = notificationListeners;
   1155 
   1156         // This is a MangedServices object that keeps track of the assistant.
   1157         mNotificationAssistants = new NotificationAssistants();
   1158 
   1159         mStatusBar = getLocalService(StatusBarManagerInternal.class);
   1160         if (mStatusBar != null) {
   1161             mStatusBar.setNotificationDelegate(mNotificationDelegate);
   1162         }
   1163 
   1164         mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
   1165         mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
   1166 
   1167         mFallbackVibrationPattern = getLongArray(resources,
   1168                 R.array.config_notificationFallbackVibePattern,
   1169                 VIBRATE_PATTERN_MAXLEN,
   1170                 DEFAULT_VIBRATE_PATTERN);
   1171 
   1172         mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
   1173 
   1174         // Don't start allowing notifications until the setup wizard has run once.
   1175         // After that, including subsequent boots, init with notifications turned on.
   1176         // This works on the first boot because the setup wizard will toggle this
   1177         // flag at least once and we'll go back to 0 after that.
   1178         if (0 == Settings.Global.getInt(getContext().getContentResolver(),
   1179                     Settings.Global.DEVICE_PROVISIONED, 0)) {
   1180             mDisableNotificationEffects = true;
   1181         }
   1182         mZenModeHelper.initZenMode();
   1183         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
   1184 
   1185         mUserProfiles.updateCache(getContext());
   1186         listenForCallState();
   1187 
   1188         // register for various Intents
   1189         IntentFilter filter = new IntentFilter();
   1190         filter.addAction(Intent.ACTION_SCREEN_ON);
   1191         filter.addAction(Intent.ACTION_SCREEN_OFF);
   1192         filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
   1193         filter.addAction(Intent.ACTION_USER_PRESENT);
   1194         filter.addAction(Intent.ACTION_USER_STOPPED);
   1195         filter.addAction(Intent.ACTION_USER_SWITCHED);
   1196         filter.addAction(Intent.ACTION_USER_ADDED);
   1197         filter.addAction(Intent.ACTION_USER_REMOVED);
   1198         filter.addAction(Intent.ACTION_USER_UNLOCKED);
   1199         filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
   1200         getContext().registerReceiver(mIntentReceiver, filter);
   1201 
   1202         IntentFilter pkgFilter = new IntentFilter();
   1203         pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
   1204         pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
   1205         pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
   1206         pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
   1207         pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
   1208         pkgFilter.addDataScheme("package");
   1209         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
   1210                 null);
   1211 
   1212         IntentFilter suspendedPkgFilter = new IntentFilter();
   1213         suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
   1214         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
   1215                 suspendedPkgFilter, null, null);
   1216 
   1217         IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
   1218         getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
   1219                 null);
   1220 
   1221         IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
   1222         timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
   1223         getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
   1224 
   1225         mSettingsObserver = new SettingsObserver(mHandler);
   1226 
   1227         mArchive = new Archive(resources.getInteger(
   1228                 R.integer.config_notificationServiceArchiveSize));
   1229 
   1230         mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
   1231                 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
   1232     }
   1233 
   1234     @Override
   1235     public void onStart() {
   1236         SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
   1237             @Override
   1238             public void repost(int userId, NotificationRecord r) {
   1239                 try {
   1240                     if (DBG) {
   1241                         Slog.d(TAG, "Reposting " + r.getKey());
   1242                     }
   1243                     enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
   1244                             r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
   1245                             r.sbn.getNotification(), userId);
   1246                 } catch (Exception e) {
   1247                     Slog.e(TAG, "Cannot un-snooze notification", e);
   1248                 }
   1249             }
   1250         }, mUserProfiles);
   1251 
   1252         init(Looper.myLooper(), AppGlobals.getPackageManager(), getContext().getPackageManager(),
   1253                 getLocalService(LightsManager.class), new NotificationListeners(),
   1254                 null, snoozeHelper, new NotificationUsageStats(getContext()));
   1255         publishBinderService(Context.NOTIFICATION_SERVICE, mService);
   1256         publishLocalService(NotificationManagerInternal.class, mInternalService);
   1257     }
   1258 
   1259     private void sendRegisteredOnlyBroadcast(String action) {
   1260         getContext().sendBroadcastAsUser(new Intent(action)
   1261                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
   1262     }
   1263 
   1264     @Override
   1265     public void onBootPhase(int phase) {
   1266         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
   1267             // no beeping until we're basically done booting
   1268             mSystemReady = true;
   1269 
   1270             // Grab our optional AudioService
   1271             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
   1272             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
   1273             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
   1274             mZenModeHelper.onSystemReady();
   1275         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
   1276             // This observer will force an update when observe is called, causing us to
   1277             // bind to listener services.
   1278             mSettingsObserver.observe();
   1279             mListeners.onBootPhaseAppsCanStart();
   1280             mNotificationAssistants.onBootPhaseAppsCanStart();
   1281             mConditionProviders.onBootPhaseAppsCanStart();
   1282         }
   1283     }
   1284 
   1285     @GuardedBy("mNotificationLock")
   1286     private void updateListenerHintsLocked() {
   1287         final int hints = calculateHints();
   1288         if (hints == mListenerHints) return;
   1289         ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
   1290         mListenerHints = hints;
   1291         scheduleListenerHintsChanged(hints);
   1292     }
   1293 
   1294     @GuardedBy("mNotificationLock")
   1295     private void updateEffectsSuppressorLocked() {
   1296         final long updatedSuppressedEffects = calculateSuppressedEffects();
   1297         if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
   1298         final List<ComponentName> suppressors = getSuppressors();
   1299         ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
   1300         mEffectsSuppressors = suppressors;
   1301         mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
   1302         sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
   1303     }
   1304 
   1305     private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
   1306             boolean fromListener) {
   1307         if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
   1308             // cancel
   1309             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
   1310                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
   1311                     null);
   1312         }
   1313         mRankingHelper.updateNotificationChannel(pkg, uid, channel);
   1314 
   1315         final NotificationChannel modifiedChannel =
   1316                 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
   1317 
   1318         if (!fromListener) {
   1319             mListeners.notifyNotificationChannelChanged(
   1320                     pkg, UserHandle.getUserHandleForUid(uid),
   1321                     modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
   1322         }
   1323 
   1324         synchronized (mNotificationLock) {
   1325             final int N = mNotificationList.size();
   1326             for (int i = N - 1; i >= 0; --i) {
   1327                 NotificationRecord r = mNotificationList.get(i);
   1328                 if (r.sbn.getPackageName().equals(pkg)
   1329                         && r.sbn.getUid() == uid
   1330                         && channel.getId() != null
   1331                         && channel.getId().equals(r.getChannel().getId())) {
   1332                     r.updateNotificationChannel(modifiedChannel);
   1333                 }
   1334             }
   1335         }
   1336         mRankingHandler.requestSort(true);
   1337         savePolicyFile();
   1338     }
   1339 
   1340     private ArrayList<ComponentName> getSuppressors() {
   1341         ArrayList<ComponentName> names = new ArrayList<ComponentName>();
   1342         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
   1343             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
   1344 
   1345             for (ManagedServiceInfo info : serviceInfoList) {
   1346                 names.add(info.component);
   1347             }
   1348         }
   1349 
   1350         return names;
   1351     }
   1352 
   1353     private boolean removeDisabledHints(ManagedServiceInfo info) {
   1354         return removeDisabledHints(info, 0);
   1355     }
   1356 
   1357     private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
   1358         boolean removed = false;
   1359 
   1360         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
   1361             final int hint = mListenersDisablingEffects.keyAt(i);
   1362             final ArraySet<ManagedServiceInfo> listeners =
   1363                     mListenersDisablingEffects.valueAt(i);
   1364 
   1365             if (hints == 0 || (hint & hints) == hint) {
   1366                 removed = removed || listeners.remove(info);
   1367             }
   1368         }
   1369 
   1370         return removed;
   1371     }
   1372 
   1373     private void addDisabledHints(ManagedServiceInfo info, int hints) {
   1374         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
   1375             addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
   1376         }
   1377 
   1378         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
   1379             addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
   1380         }
   1381 
   1382         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
   1383             addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
   1384         }
   1385     }
   1386 
   1387     private void addDisabledHint(ManagedServiceInfo info, int hint) {
   1388         if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
   1389             mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
   1390         }
   1391 
   1392         ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
   1393         hintListeners.add(info);
   1394     }
   1395 
   1396     private int calculateHints() {
   1397         int hints = 0;
   1398         for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
   1399             int hint = mListenersDisablingEffects.keyAt(i);
   1400             ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
   1401 
   1402             if (!serviceInfoList.isEmpty()) {
   1403                 hints |= hint;
   1404             }
   1405         }
   1406 
   1407         return hints;
   1408     }
   1409 
   1410     private long calculateSuppressedEffects() {
   1411         int hints = calculateHints();
   1412         long suppressedEffects = 0;
   1413 
   1414         if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
   1415             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
   1416         }
   1417 
   1418         if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
   1419             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
   1420         }
   1421 
   1422         if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
   1423             suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
   1424         }
   1425 
   1426         return suppressedEffects;
   1427     }
   1428 
   1429     @GuardedBy("mNotificationLock")
   1430     private void updateInterruptionFilterLocked() {
   1431         int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
   1432         if (interruptionFilter == mInterruptionFilter) return;
   1433         mInterruptionFilter = interruptionFilter;
   1434         scheduleInterruptionFilterChanged(interruptionFilter);
   1435     }
   1436 
   1437     @VisibleForTesting
   1438     INotificationManager getBinderService() {
   1439         return INotificationManager.Stub.asInterface(mService);
   1440     }
   1441 
   1442     @VisibleForTesting
   1443     NotificationManagerInternal getInternalService() {
   1444         return mInternalService;
   1445     }
   1446 
   1447     private final IBinder mService = new INotificationManager.Stub() {
   1448         // Toasts
   1449         // ============================================================================
   1450 
   1451         @Override
   1452         public void enqueueToast(String pkg, ITransientNotification callback, int duration)
   1453         {
   1454             if (DBG) {
   1455                 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
   1456                         + " duration=" + duration);
   1457             }
   1458 
   1459             if (pkg == null || callback == null) {
   1460                 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
   1461                 return ;
   1462             }
   1463 
   1464             final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
   1465             final boolean isPackageSuspended =
   1466                     isPackageSuspendedForUser(pkg, Binder.getCallingUid());
   1467 
   1468             if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
   1469                     (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
   1470                             || isPackageSuspended)) {
   1471                 Slog.e(TAG, "Suppressing toast from package " + pkg
   1472                         + (isPackageSuspended
   1473                                 ? " due to package suspended by administrator."
   1474                                 : " by user request."));
   1475                 return;
   1476             }
   1477 
   1478             synchronized (mToastQueue) {
   1479                 int callingPid = Binder.getCallingPid();
   1480                 long callingId = Binder.clearCallingIdentity();
   1481                 try {
   1482                     ToastRecord record;
   1483                     int index = indexOfToastLocked(pkg, callback);
   1484                     // If it's already in the queue, we update it in place, we don't
   1485                     // move it to the end of the queue.
   1486                     if (index >= 0) {
   1487                         record = mToastQueue.get(index);
   1488                         record.update(duration);
   1489                     } else {
   1490                         // Limit the number of toasts that any given package except the android
   1491                         // package can enqueue.  Prevents DOS attacks and deals with leaks.
   1492                         if (!isSystemToast) {
   1493                             int count = 0;
   1494                             final int N = mToastQueue.size();
   1495                             for (int i=0; i<N; i++) {
   1496                                  final ToastRecord r = mToastQueue.get(i);
   1497                                  if (r.pkg.equals(pkg)) {
   1498                                      count++;
   1499                                      if (count >= MAX_PACKAGE_NOTIFICATIONS) {
   1500                                          Slog.e(TAG, "Package has already posted " + count
   1501                                                 + " toasts. Not showing more. Package=" + pkg);
   1502                                          return;
   1503                                      }
   1504                                  }
   1505                             }
   1506                         }
   1507 
   1508                         Binder token = new Binder();
   1509                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
   1510                         record = new ToastRecord(callingPid, pkg, callback, duration, token);
   1511                         mToastQueue.add(record);
   1512                         index = mToastQueue.size() - 1;
   1513                         keepProcessAliveIfNeededLocked(callingPid);
   1514                     }
   1515                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
   1516                     // new or just been updated.  Call back and tell it to show itself.
   1517                     // If the callback fails, this will remove it from the list, so don't
   1518                     // assume that it's valid after this.
   1519                     if (index == 0) {
   1520                         showNextToastLocked();
   1521                     }
   1522                 } finally {
   1523                     Binder.restoreCallingIdentity(callingId);
   1524                 }
   1525             }
   1526         }
   1527 
   1528         @Override
   1529         public void cancelToast(String pkg, ITransientNotification callback) {
   1530             Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
   1531 
   1532             if (pkg == null || callback == null) {
   1533                 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
   1534                 return ;
   1535             }
   1536 
   1537             synchronized (mToastQueue) {
   1538                 long callingId = Binder.clearCallingIdentity();
   1539                 try {
   1540                     int index = indexOfToastLocked(pkg, callback);
   1541                     if (index >= 0) {
   1542                         cancelToastLocked(index);
   1543                     } else {
   1544                         Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
   1545                                 + " callback=" + callback);
   1546                     }
   1547                 } finally {
   1548                     Binder.restoreCallingIdentity(callingId);
   1549                 }
   1550             }
   1551         }
   1552 
   1553         @Override
   1554         public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
   1555                 Notification notification, int userId) throws RemoteException {
   1556             enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
   1557                     Binder.getCallingPid(), tag, id, notification, userId);
   1558         }
   1559 
   1560         @Override
   1561         public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
   1562             checkCallerIsSystemOrSameApp(pkg);
   1563             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
   1564                     Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
   1565             // Don't allow client applications to cancel foreground service notis or autobundled
   1566             // summaries.
   1567             final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
   1568                     (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
   1569             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
   1570                     mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
   1571         }
   1572 
   1573         @Override
   1574         public void cancelAllNotifications(String pkg, int userId) {
   1575             checkCallerIsSystemOrSameApp(pkg);
   1576 
   1577             userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
   1578                     Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
   1579 
   1580             // Calling from user space, don't allow the canceling of actively
   1581             // running foreground services.
   1582             cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
   1583                     pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
   1584                     REASON_APP_CANCEL_ALL, null);
   1585         }
   1586 
   1587         @Override
   1588         public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
   1589             checkCallerIsSystem();
   1590 
   1591             mRankingHelper.setEnabled(pkg, uid, enabled);
   1592             // Now, cancel any outstanding notifications that are part of a just-disabled app
   1593             if (!enabled) {
   1594                 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
   1595                         UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
   1596             }
   1597             savePolicyFile();
   1598         }
   1599 
   1600         /**
   1601          * Use this when you just want to know if notifications are OK for this package.
   1602          */
   1603         @Override
   1604         public boolean areNotificationsEnabled(String pkg) {
   1605             return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
   1606         }
   1607 
   1608         /**
   1609          * Use this when you just want to know if notifications are OK for this package.
   1610          */
   1611         @Override
   1612         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
   1613             checkCallerIsSystemOrSameApp(pkg);
   1614 
   1615             return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
   1616         }
   1617 
   1618         @Override
   1619         public int getPackageImportance(String pkg) {
   1620             checkCallerIsSystemOrSameApp(pkg);
   1621             return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
   1622         }
   1623 
   1624         @Override
   1625         public boolean canShowBadge(String pkg, int uid) {
   1626             checkCallerIsSystem();
   1627             return mRankingHelper.canShowBadge(pkg, uid);
   1628         }
   1629 
   1630         @Override
   1631         public void setShowBadge(String pkg, int uid, boolean showBadge) {
   1632             checkCallerIsSystem();
   1633             mRankingHelper.setShowBadge(pkg, uid, showBadge);
   1634             savePolicyFile();
   1635         }
   1636 
   1637         @Override
   1638         public void createNotificationChannelGroups(String pkg,
   1639                 ParceledListSlice channelGroupList) throws RemoteException {
   1640             checkCallerIsSystemOrSameApp(pkg);
   1641             List<NotificationChannelGroup> groups = channelGroupList.getList();
   1642             final int groupSize = groups.size();
   1643             for (int i = 0; i < groupSize; i++) {
   1644                 final NotificationChannelGroup group = groups.get(i);
   1645                 Preconditions.checkNotNull(group, "group in list is null");
   1646                 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
   1647                         true /* fromTargetApp */);
   1648                 mListeners.notifyNotificationChannelGroupChanged(pkg,
   1649                         UserHandle.of(UserHandle.getCallingUserId()), group,
   1650                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
   1651             }
   1652             savePolicyFile();
   1653         }
   1654 
   1655         private void createNotificationChannelsImpl(String pkg, int uid,
   1656                 ParceledListSlice channelsList) {
   1657             List<NotificationChannel> channels = channelsList.getList();
   1658             final int channelsSize = channels.size();
   1659             for (int i = 0; i < channelsSize; i++) {
   1660                 final NotificationChannel channel = channels.get(i);
   1661                 Preconditions.checkNotNull(channel, "channel in list is null");
   1662                 mRankingHelper.createNotificationChannel(pkg, uid, channel,
   1663                         true /* fromTargetApp */);
   1664                 mListeners.notifyNotificationChannelChanged(pkg,
   1665                         UserHandle.getUserHandleForUid(uid),
   1666                         mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
   1667                         NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
   1668             }
   1669             savePolicyFile();
   1670         }
   1671 
   1672         @Override
   1673         public void createNotificationChannels(String pkg,
   1674                 ParceledListSlice channelsList) throws RemoteException {
   1675             checkCallerIsSystemOrSameApp(pkg);
   1676             createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
   1677         }
   1678 
   1679         @Override
   1680         public void createNotificationChannelsForPackage(String pkg, int uid,
   1681                 ParceledListSlice channelsList) throws RemoteException {
   1682             checkCallerIsSystem();
   1683             createNotificationChannelsImpl(pkg, uid, channelsList);
   1684         }
   1685 
   1686         @Override
   1687         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
   1688             checkCallerIsSystemOrSameApp(pkg);
   1689             return mRankingHelper.getNotificationChannel(
   1690                     pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
   1691         }
   1692 
   1693         @Override
   1694         public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
   1695                 String channelId, boolean includeDeleted) {
   1696             checkCallerIsSystem();
   1697             return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
   1698         }
   1699 
   1700         @Override
   1701         public void deleteNotificationChannel(String pkg, String channelId) {
   1702             checkCallerIsSystemOrSameApp(pkg);
   1703             final int callingUid = Binder.getCallingUid();
   1704             if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
   1705                 throw new IllegalArgumentException("Cannot delete default channel");
   1706             }
   1707             cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
   1708                     UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
   1709             mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
   1710             mListeners.notifyNotificationChannelChanged(pkg,
   1711                     UserHandle.getUserHandleForUid(callingUid),
   1712                     mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
   1713                     NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
   1714             savePolicyFile();
   1715         }
   1716 
   1717         @Override
   1718         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
   1719                 String pkg) {
   1720             checkCallerIsSystemOrSameApp(pkg);
   1721             return new ParceledListSlice<>(new ArrayList(
   1722                     mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
   1723         }
   1724 
   1725         @Override
   1726         public void deleteNotificationChannelGroup(String pkg, String groupId) {
   1727             checkCallerIsSystemOrSameApp(pkg);
   1728 
   1729             final int callingUid = Binder.getCallingUid();
   1730             NotificationChannelGroup groupToDelete =
   1731                     mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
   1732             if (groupToDelete != null) {
   1733                 List<NotificationChannel> deletedChannels =
   1734                         mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
   1735                 for (int i = 0; i < deletedChannels.size(); i++) {
   1736                     final NotificationChannel deletedChannel = deletedChannels.get(i);
   1737                     cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
   1738                             true,
   1739                             UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
   1740                             null);
   1741                     mListeners.notifyNotificationChannelChanged(pkg,
   1742                             UserHandle.getUserHandleForUid(callingUid),
   1743                             deletedChannel,
   1744                             NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
   1745                 }
   1746                 mListeners.notifyNotificationChannelGroupChanged(
   1747                         pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
   1748                         NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
   1749                 savePolicyFile();
   1750             }
   1751         }
   1752 
   1753         @Override
   1754         public void updateNotificationChannelForPackage(String pkg, int uid,
   1755                 NotificationChannel channel) {
   1756             enforceSystemOrSystemUI("Caller not system or systemui");
   1757             Preconditions.checkNotNull(channel);
   1758             updateNotificationChannelInt(pkg, uid, channel, false);
   1759         }
   1760 
   1761         @Override
   1762         public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
   1763                 int uid, boolean includeDeleted) {
   1764             enforceSystemOrSystemUI("getNotificationChannelsForPackage");
   1765             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
   1766         }
   1767 
   1768         @Override
   1769         public int getNumNotificationChannelsForPackage(String pkg, int uid,
   1770                 boolean includeDeleted) {
   1771             enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
   1772             return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
   1773                     .getList().size();
   1774         }
   1775 
   1776         @Override
   1777         public boolean onlyHasDefaultChannel(String pkg, int uid) {
   1778             enforceSystemOrSystemUI("onlyHasDefaultChannel");
   1779             return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
   1780         }
   1781 
   1782         @Override
   1783         public int getDeletedChannelCount(String pkg, int uid) {
   1784             enforceSystemOrSystemUI("getDeletedChannelCount");
   1785             return mRankingHelper.getDeletedChannelCount(pkg, uid);
   1786         }
   1787 
   1788         @Override
   1789         public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
   1790                 String pkg, int uid, boolean includeDeleted) {
   1791             checkCallerIsSystem();
   1792             return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
   1793         }
   1794 
   1795         @Override
   1796         public NotificationChannelGroup getNotificationChannelGroupForPackage(
   1797                 String groupId, String pkg, int uid) {
   1798             enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
   1799             return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
   1800         }
   1801 
   1802         @Override
   1803         public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
   1804             checkCallerIsSystemOrSameApp(pkg);
   1805             return mRankingHelper.getNotificationChannels(
   1806                     pkg, Binder.getCallingUid(), false /* includeDeleted */);
   1807         }
   1808 
   1809         @Override
   1810         public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
   1811             checkCallerIsSystem();
   1812 
   1813             // Cancel posted notifications
   1814             cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
   1815                     UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
   1816 
   1817             // Listener & assistant
   1818             mListeners.onPackagesChanged(true, new String[] {packageName});
   1819             mNotificationAssistants.onPackagesChanged(true, new String[] {packageName});
   1820 
   1821             // Zen
   1822             mConditionProviders.onPackagesChanged(true, new String[] {packageName});
   1823 
   1824             // Reset notification preferences
   1825             if (!fromApp) {
   1826                 mRankingHelper.onPackagesChanged(true, UserHandle.getCallingUserId(),
   1827                         new String[]{packageName}, new int[]{uid});
   1828             }
   1829 
   1830             savePolicyFile();
   1831         }
   1832 
   1833 
   1834         /**
   1835          * System-only API for getting a list of current (i.e. not cleared) notifications.
   1836          *
   1837          * Requires ACCESS_NOTIFICATIONS which is signature|system.
   1838          * @returns A list of all the notifications, in natural order.
   1839          */
   1840         @Override
   1841         public StatusBarNotification[] getActiveNotifications(String callingPkg) {
   1842             // enforce() will ensure the calling uid has the correct permission
   1843             getContext().enforceCallingOrSelfPermission(
   1844                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
   1845                     "NotificationManagerService.getActiveNotifications");
   1846 
   1847             StatusBarNotification[] tmp = null;
   1848             int uid = Binder.getCallingUid();
   1849 
   1850             // noteOp will check to make sure the callingPkg matches the uid
   1851             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
   1852                     == AppOpsManager.MODE_ALLOWED) {
   1853                 synchronized (mNotificationLock) {
   1854                     tmp = new StatusBarNotification[mNotificationList.size()];
   1855                     final int N = mNotificationList.size();
   1856                     for (int i=0; i<N; i++) {
   1857                         tmp[i] = mNotificationList.get(i).sbn;
   1858                     }
   1859                 }
   1860             }
   1861             return tmp;
   1862         }
   1863 
   1864         /**
   1865          * Public API for getting a list of current notifications for the calling package/uid.
   1866          *
   1867          * Note that since notification posting is done asynchronously, this will not return
   1868          * notifications that are in the process of being posted.
   1869          *
   1870          * @returns A list of all the package's notifications, in natural order.
   1871          */
   1872         @Override
   1873         public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
   1874                 int incomingUserId) {
   1875             checkCallerIsSystemOrSameApp(pkg);
   1876             int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
   1877                     Binder.getCallingUid(), incomingUserId, true, false,
   1878                     "getAppActiveNotifications", pkg);
   1879             synchronized (mNotificationLock) {
   1880                 final ArrayMap<String, StatusBarNotification> map
   1881                         = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
   1882                 final int N = mNotificationList.size();
   1883                 for (int i = 0; i < N; i++) {
   1884                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
   1885                             mNotificationList.get(i).sbn);
   1886                     if (sbn != null) {
   1887                         map.put(sbn.getKey(), sbn);
   1888                     }
   1889                 }
   1890                 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
   1891                     StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
   1892                     if (sbn != null) {
   1893                         map.put(sbn.getKey(), sbn);
   1894                     }
   1895                 }
   1896                 final int M = mEnqueuedNotifications.size();
   1897                 for (int i = 0; i < M; i++) {
   1898                     StatusBarNotification sbn = sanitizeSbn(pkg, userId,
   1899                             mEnqueuedNotifications.get(i).sbn);
   1900                     if (sbn != null) {
   1901                         map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
   1902                     }
   1903                 }
   1904                 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
   1905                 list.addAll(map.values());
   1906                 return new ParceledListSlice<StatusBarNotification>(list);
   1907             }
   1908         }
   1909 
   1910         private StatusBarNotification sanitizeSbn(String pkg, int userId,
   1911                 StatusBarNotification sbn) {
   1912             if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
   1913                     && (sbn.getNotification().flags
   1914                     & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
   1915                 // We could pass back a cloneLight() but clients might get confused and
   1916                 // try to send this thing back to notify() again, which would not work
   1917                 // very well.
   1918                 return new StatusBarNotification(
   1919                         sbn.getPackageName(),
   1920                         sbn.getOpPkg(),
   1921                         sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
   1922                         sbn.getNotification().clone(),
   1923                         sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
   1924             }
   1925             return null;
   1926         }
   1927 
   1928         /**
   1929          * System-only API for getting a list of recent (cleared, no longer shown) notifications.
   1930          *
   1931          * Requires ACCESS_NOTIFICATIONS which is signature|system.
   1932          */
   1933         @Override
   1934         public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
   1935             // enforce() will ensure the calling uid has the correct permission
   1936             getContext().enforceCallingOrSelfPermission(
   1937                     android.Manifest.permission.ACCESS_NOTIFICATIONS,
   1938                     "NotificationManagerService.getHistoricalNotifications");
   1939 
   1940             StatusBarNotification[] tmp = null;
   1941             int uid = Binder.getCallingUid();
   1942 
   1943             // noteOp will check to make sure the callingPkg matches the uid
   1944             if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
   1945                     == AppOpsManager.MODE_ALLOWED) {
   1946                 synchronized (mArchive) {
   1947                     tmp = mArchive.getArray(count);
   1948                 }
   1949             }
   1950             return tmp;
   1951         }
   1952 
   1953         /**
   1954          * Register a listener binder directly with the notification manager.
   1955          *
   1956          * Only works with system callers. Apps should extend
   1957          * {@link android.service.notification.NotificationListenerService}.
   1958          */
   1959         @Override
   1960         public void registerListener(final INotificationListener listener,
   1961                 final ComponentName component, final int userid) {
   1962             enforceSystemOrSystemUI("INotificationManager.registerListener");
   1963             mListeners.registerService(listener, component, userid);
   1964         }
   1965 
   1966         /**
   1967          * Remove a listener binder directly
   1968          */
   1969         @Override
   1970         public void unregisterListener(INotificationListener token, int userid) {
   1971             mListeners.unregisterService(token, userid);
   1972         }
   1973 
   1974         /**
   1975          * Allow an INotificationListener to simulate a "clear all" operation.
   1976          *
   1977          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
   1978          *
   1979          * @param token The binder for the listener, to check that the caller is allowed
   1980          */
   1981         @Override
   1982         public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
   1983             final int callingUid = Binder.getCallingUid();
   1984             final int callingPid = Binder.getCallingPid();
   1985             long identity = Binder.clearCallingIdentity();
   1986             try {
   1987                 synchronized (mNotificationLock) {
   1988                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   1989                     if (keys != null) {
   1990                         final int N = keys.length;
   1991                         for (int i = 0; i < N; i++) {
   1992                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
   1993                             if (r == null) continue;
   1994                             final int userId = r.sbn.getUserId();
   1995                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
   1996                                     !mUserProfiles.isCurrentProfile(userId)) {
   1997                                 throw new SecurityException("Disallowed call from listener: "
   1998                                         + info.service);
   1999                             }
   2000                             cancelNotificationFromListenerLocked(info, callingUid, callingPid,
   2001                                     r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
   2002                                     userId);
   2003                         }
   2004                     } else {
   2005                         cancelAllLocked(callingUid, callingPid, info.userid,
   2006                                 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
   2007                     }
   2008                 }
   2009             } finally {
   2010                 Binder.restoreCallingIdentity(identity);
   2011             }
   2012         }
   2013 
   2014         /**
   2015          * Handle request from an approved listener to re-enable itself.
   2016          *
   2017          * @param component The componenet to be re-enabled, caller must match package.
   2018          */
   2019         @Override
   2020         public void requestBindListener(ComponentName component) {
   2021             checkCallerIsSystemOrSameApp(component.getPackageName());
   2022             long identity = Binder.clearCallingIdentity();
   2023             try {
   2024                 ManagedServices manager =
   2025                         mNotificationAssistants.isComponentEnabledForCurrentProfiles(component)
   2026                         ? mNotificationAssistants
   2027                         : mListeners;
   2028                 manager.setComponentState(component, true);
   2029             } finally {
   2030                 Binder.restoreCallingIdentity(identity);
   2031             }
   2032         }
   2033 
   2034         @Override
   2035         public void requestUnbindListener(INotificationListener token) {
   2036             long identity = Binder.clearCallingIdentity();
   2037             try {
   2038                 // allow bound services to disable themselves
   2039                 synchronized (mNotificationLock) {
   2040                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2041                     info.getOwner().setComponentState(info.component, false);
   2042                 }
   2043             } finally {
   2044                 Binder.restoreCallingIdentity(identity);
   2045             }
   2046         }
   2047 
   2048         @Override
   2049         public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
   2050             long identity = Binder.clearCallingIdentity();
   2051             try {
   2052                 synchronized (mNotificationLock) {
   2053                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2054                     if (keys != null) {
   2055                         final int N = keys.length;
   2056                         for (int i = 0; i < N; i++) {
   2057                             NotificationRecord r = mNotificationsByKey.get(keys[i]);
   2058                             if (r == null) continue;
   2059                             final int userId = r.sbn.getUserId();
   2060                             if (userId != info.userid && userId != UserHandle.USER_ALL &&
   2061                                     !mUserProfiles.isCurrentProfile(userId)) {
   2062                                 throw new SecurityException("Disallowed call from listener: "
   2063                                         + info.service);
   2064                             }
   2065                             if (!r.isSeen()) {
   2066                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
   2067                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
   2068                                         userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
   2069                                                 : userId,
   2070                                         UsageEvents.Event.USER_INTERACTION);
   2071                                 r.setSeen();
   2072                             }
   2073                         }
   2074                     }
   2075                 }
   2076             } finally {
   2077                 Binder.restoreCallingIdentity(identity);
   2078             }
   2079         }
   2080 
   2081         /**
   2082          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
   2083          *
   2084          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
   2085          *
   2086          * @param info The binder for the listener, to check that the caller is allowed
   2087          */
   2088         @GuardedBy("mNotificationLock")
   2089         private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
   2090                 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
   2091             cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
   2092                     Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
   2093                     true,
   2094                     userId, REASON_LISTENER_CANCEL, info);
   2095         }
   2096 
   2097         /**
   2098          * Allow an INotificationListener to snooze a single notification until a context.
   2099          *
   2100          * @param token The binder for the listener, to check that the caller is allowed
   2101          */
   2102         @Override
   2103         public void snoozeNotificationUntilContextFromListener(INotificationListener token,
   2104                 String key, String snoozeCriterionId) {
   2105             long identity = Binder.clearCallingIdentity();
   2106             try {
   2107                 synchronized (mNotificationLock) {
   2108                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2109                     snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
   2110                 }
   2111             } finally {
   2112                 Binder.restoreCallingIdentity(identity);
   2113             }
   2114         }
   2115 
   2116         /**
   2117          * Allow an INotificationListener to snooze a single notification until a time.
   2118          *
   2119          * @param token The binder for the listener, to check that the caller is allowed
   2120          */
   2121         @Override
   2122         public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
   2123                 long duration) {
   2124             long identity = Binder.clearCallingIdentity();
   2125             try {
   2126                 synchronized (mNotificationLock) {
   2127                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2128                     snoozeNotificationInt(key, duration, null, info);
   2129                 }
   2130             } finally {
   2131                 Binder.restoreCallingIdentity(identity);
   2132             }
   2133         }
   2134 
   2135         /**
   2136          * Allows the notification assistant to un-snooze a single notification.
   2137          *
   2138          * @param token The binder for the assistant, to check that the caller is allowed
   2139          */
   2140         @Override
   2141         public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
   2142             long identity = Binder.clearCallingIdentity();
   2143             try {
   2144                 synchronized (mNotificationLock) {
   2145                     final ManagedServiceInfo info =
   2146                             mNotificationAssistants.checkServiceTokenLocked(token);
   2147                     unsnoozeNotificationInt(key, info);
   2148                 }
   2149             } finally {
   2150                 Binder.restoreCallingIdentity(identity);
   2151             }
   2152         }
   2153 
   2154         /**
   2155          * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
   2156          *
   2157          * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
   2158          *
   2159          * @param token The binder for the listener, to check that the caller is allowed
   2160          */
   2161         @Override
   2162         public void cancelNotificationFromListener(INotificationListener token, String pkg,
   2163                 String tag, int id) {
   2164             final int callingUid = Binder.getCallingUid();
   2165             final int callingPid = Binder.getCallingPid();
   2166             long identity = Binder.clearCallingIdentity();
   2167             try {
   2168                 synchronized (mNotificationLock) {
   2169                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2170                     if (info.supportsProfiles()) {
   2171                         Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
   2172                                 + "from " + info.component
   2173                                 + " use cancelNotification(key) instead.");
   2174                     } else {
   2175                         cancelNotificationFromListenerLocked(info, callingUid, callingPid,
   2176                                 pkg, tag, id, info.userid);
   2177                     }
   2178                 }
   2179             } finally {
   2180                 Binder.restoreCallingIdentity(identity);
   2181             }
   2182         }
   2183 
   2184         /**
   2185          * Allow an INotificationListener to request the list of outstanding notifications seen by
   2186          * the current user. Useful when starting up, after which point the listener callbacks
   2187          * should be used.
   2188          *
   2189          * @param token The binder for the listener, to check that the caller is allowed
   2190          * @param keys An array of notification keys to fetch, or null to fetch everything
   2191          * @returns The return value will contain the notifications specified in keys, in that
   2192          *      order, or if keys is null, all the notifications, in natural order.
   2193          */
   2194         @Override
   2195         public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
   2196                 INotificationListener token, String[] keys, int trim) {
   2197             synchronized (mNotificationLock) {
   2198                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2199                 final boolean getKeys = keys != null;
   2200                 final int N = getKeys ? keys.length : mNotificationList.size();
   2201                 final ArrayList<StatusBarNotification> list
   2202                         = new ArrayList<StatusBarNotification>(N);
   2203                 for (int i=0; i<N; i++) {
   2204                     final NotificationRecord r = getKeys
   2205                             ? mNotificationsByKey.get(keys[i])
   2206                             : mNotificationList.get(i);
   2207                     if (r == null) continue;
   2208                     StatusBarNotification sbn = r.sbn;
   2209                     if (!isVisibleToListener(sbn, info)) continue;
   2210                     StatusBarNotification sbnToSend =
   2211                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
   2212                     list.add(sbnToSend);
   2213                 }
   2214                 return new ParceledListSlice<StatusBarNotification>(list);
   2215             }
   2216         }
   2217 
   2218         /**
   2219          * Allow an INotificationListener to request the list of outstanding snoozed notifications
   2220          * seen by the current user. Useful when starting up, after which point the listener
   2221          * callbacks should be used.
   2222          *
   2223          * @param token The binder for the listener, to check that the caller is allowed
   2224          * @returns The return value will contain the notifications specified in keys, in that
   2225          *      order, or if keys is null, all the notifications, in natural order.
   2226          */
   2227         @Override
   2228         public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
   2229                 INotificationListener token, int trim) {
   2230             synchronized (mNotificationLock) {
   2231                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2232                 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
   2233                 final int N = snoozedRecords.size();
   2234                 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
   2235                 for (int i=0; i < N; i++) {
   2236                     final NotificationRecord r = snoozedRecords.get(i);
   2237                     if (r == null) continue;
   2238                     StatusBarNotification sbn = r.sbn;
   2239                     if (!isVisibleToListener(sbn, info)) continue;
   2240                     StatusBarNotification sbnToSend =
   2241                             (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
   2242                     list.add(sbnToSend);
   2243                 }
   2244                 return new ParceledListSlice<>(list);
   2245             }
   2246         }
   2247 
   2248         @Override
   2249         public void requestHintsFromListener(INotificationListener token, int hints) {
   2250             final long identity = Binder.clearCallingIdentity();
   2251             try {
   2252                 synchronized (mNotificationLock) {
   2253                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2254                     final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
   2255                             | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
   2256                             | HINT_HOST_DISABLE_CALL_EFFECTS;
   2257                     final boolean disableEffects = (hints & disableEffectsMask) != 0;
   2258                     if (disableEffects) {
   2259                         addDisabledHints(info, hints);
   2260                     } else {
   2261                         removeDisabledHints(info, hints);
   2262                     }
   2263                     updateListenerHintsLocked();
   2264                     updateEffectsSuppressorLocked();
   2265                 }
   2266             } finally {
   2267                 Binder.restoreCallingIdentity(identity);
   2268             }
   2269         }
   2270 
   2271         @Override
   2272         public int getHintsFromListener(INotificationListener token) {
   2273             synchronized (mNotificationLock) {
   2274                 return mListenerHints;
   2275             }
   2276         }
   2277 
   2278         @Override
   2279         public void requestInterruptionFilterFromListener(INotificationListener token,
   2280                 int interruptionFilter) throws RemoteException {
   2281             final long identity = Binder.clearCallingIdentity();
   2282             try {
   2283                 synchronized (mNotificationLock) {
   2284                     final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2285                     mZenModeHelper.requestFromListener(info.component, interruptionFilter);
   2286                     updateInterruptionFilterLocked();
   2287                 }
   2288             } finally {
   2289                 Binder.restoreCallingIdentity(identity);
   2290             }
   2291         }
   2292 
   2293         @Override
   2294         public int getInterruptionFilterFromListener(INotificationListener token)
   2295                 throws RemoteException {
   2296             synchronized (mNotificationLight) {
   2297                 return mInterruptionFilter;
   2298             }
   2299         }
   2300 
   2301         @Override
   2302         public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
   2303                 throws RemoteException {
   2304             synchronized (mNotificationLock) {
   2305                 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
   2306                 if (info == null) return;
   2307                 mListeners.setOnNotificationPostedTrimLocked(info, trim);
   2308             }
   2309         }
   2310 
   2311         @Override
   2312         public int getZenMode() {
   2313             return mZenModeHelper.getZenMode();
   2314         }
   2315 
   2316         @Override
   2317         public ZenModeConfig getZenModeConfig() {
   2318             enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
   2319             return mZenModeHelper.getConfig();
   2320         }
   2321 
   2322         @Override
   2323         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
   2324             enforceSystemOrSystemUI("INotificationManager.setZenMode");
   2325             final long identity = Binder.clearCallingIdentity();
   2326             try {
   2327                 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
   2328             } finally {
   2329                 Binder.restoreCallingIdentity(identity);
   2330             }
   2331         }
   2332 
   2333         @Override
   2334         public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
   2335             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
   2336             return mZenModeHelper.getZenRules();
   2337         }
   2338 
   2339         @Override
   2340         public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
   2341             Preconditions.checkNotNull(id, "Id is null");
   2342             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
   2343             return mZenModeHelper.getAutomaticZenRule(id);
   2344         }
   2345 
   2346         @Override
   2347         public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
   2348                 throws RemoteException {
   2349             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
   2350             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
   2351             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
   2352             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
   2353             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
   2354 
   2355             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
   2356                     "addAutomaticZenRule");
   2357         }
   2358 
   2359         @Override
   2360         public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
   2361                 throws RemoteException {
   2362             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
   2363             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
   2364             Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
   2365             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
   2366             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
   2367 
   2368             return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
   2369                     "updateAutomaticZenRule");
   2370         }
   2371 
   2372         @Override
   2373         public boolean removeAutomaticZenRule(String id) throws RemoteException {
   2374             Preconditions.checkNotNull(id, "Id is null");
   2375             // Verify that they can modify zen rules.
   2376             enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
   2377 
   2378             return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
   2379         }
   2380 
   2381         @Override
   2382         public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
   2383             Preconditions.checkNotNull(packageName, "Package name is null");
   2384             enforceSystemOrSystemUI("removeAutomaticZenRules");
   2385 
   2386             return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
   2387         }
   2388 
   2389         @Override
   2390         public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
   2391             Preconditions.checkNotNull(owner, "Owner is null");
   2392             enforceSystemOrSystemUI("getRuleInstanceCount");
   2393 
   2394             return mZenModeHelper.getCurrentInstanceCount(owner);
   2395         }
   2396 
   2397         @Override
   2398         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
   2399             enforcePolicyAccess(pkg, "setInterruptionFilter");
   2400             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
   2401             if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
   2402             final long identity = Binder.clearCallingIdentity();
   2403             try {
   2404                 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
   2405             } finally {
   2406                 Binder.restoreCallingIdentity(identity);
   2407             }
   2408         }
   2409 
   2410         @Override
   2411         public void notifyConditions(final String pkg, IConditionProvider provider,
   2412                 final Condition[] conditions) {
   2413             final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
   2414             checkCallerIsSystemOrSameApp(pkg);
   2415             mHandler.post(new Runnable() {
   2416                 @Override
   2417                 public void run() {
   2418                     mConditionProviders.notifyConditions(pkg, info, conditions);
   2419                 }
   2420             });
   2421         }
   2422 
   2423         @Override
   2424         public void requestUnbindProvider(IConditionProvider provider) {
   2425             long identity = Binder.clearCallingIdentity();
   2426             try {
   2427                 // allow bound services to disable themselves
   2428                 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
   2429                 info.getOwner().setComponentState(info.component, false);
   2430             } finally {
   2431                 Binder.restoreCallingIdentity(identity);
   2432             }
   2433         }
   2434 
   2435         @Override
   2436         public void requestBindProvider(ComponentName component) {
   2437             checkCallerIsSystemOrSameApp(component.getPackageName());
   2438             long identity = Binder.clearCallingIdentity();
   2439             try {
   2440                 mConditionProviders.setComponentState(component, true);
   2441             } finally {
   2442                 Binder.restoreCallingIdentity(identity);
   2443             }
   2444         }
   2445 
   2446         private void enforceSystemOrSystemUI(String message) {
   2447             if (isCallerSystemOrPhone()) return;
   2448             getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
   2449                     message);
   2450         }
   2451 
   2452         private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
   2453             try {
   2454                 checkCallerIsSystemOrSameApp(pkg);
   2455             } catch (SecurityException e) {
   2456                 getContext().enforceCallingPermission(
   2457                         android.Manifest.permission.STATUS_BAR_SERVICE,
   2458                         message);
   2459             }
   2460         }
   2461 
   2462         private void enforcePolicyAccess(int uid, String method) {
   2463             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
   2464                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
   2465                 return;
   2466             }
   2467             boolean accessAllowed = false;
   2468             String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
   2469             final int packageCount = packages.length;
   2470             for (int i = 0; i < packageCount; i++) {
   2471                 if (checkPolicyAccess(packages[i])) {
   2472                     accessAllowed = true;
   2473                 }
   2474             }
   2475             if (!accessAllowed) {
   2476                 Slog.w(TAG, "Notification policy access denied calling " + method);
   2477                 throw new SecurityException("Notification policy access denied");
   2478             }
   2479         }
   2480 
   2481         private void enforcePolicyAccess(String pkg, String method) {
   2482             if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
   2483                     android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
   2484                 return;
   2485             }
   2486             checkCallerIsSameApp(pkg);
   2487             if (!checkPolicyAccess(pkg)) {
   2488                 Slog.w(TAG, "Notification policy access denied calling " + method);
   2489                 throw new SecurityException("Notification policy access denied");
   2490             }
   2491         }
   2492 
   2493         private boolean checkPackagePolicyAccess(String pkg) {
   2494             return mPolicyAccess.isPackageGranted(pkg);
   2495         }
   2496 
   2497         private boolean checkPolicyAccess(String pkg) {
   2498             try {
   2499                 int uid = getContext().getPackageManager().getPackageUidAsUser(
   2500                         pkg, UserHandle.getCallingUserId());
   2501                 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
   2502                         android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
   2503                         -1, true)) {
   2504                     return true;
   2505                 }
   2506             } catch (NameNotFoundException e) {
   2507                 return false;
   2508             }
   2509             return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
   2510         }
   2511 
   2512         @Override
   2513         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   2514             if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
   2515             final DumpFilter filter = DumpFilter.parseFromArguments(args);
   2516             if (filter != null && filter.stats) {
   2517                 dumpJson(pw, filter);
   2518             } else if (filter != null && filter.proto) {
   2519                 dumpProto(fd, filter);
   2520             } else {
   2521                 dumpImpl(pw, filter);
   2522             }
   2523         }
   2524 
   2525         @Override
   2526         public ComponentName getEffectsSuppressor() {
   2527             return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
   2528         }
   2529 
   2530         @Override
   2531         public boolean matchesCallFilter(Bundle extras) {
   2532             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
   2533             return mZenModeHelper.matchesCallFilter(
   2534                     Binder.getCallingUserHandle(),
   2535                     extras,
   2536                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
   2537                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
   2538                     MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
   2539         }
   2540 
   2541         @Override
   2542         public boolean isSystemConditionProviderEnabled(String path) {
   2543             enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
   2544             return mConditionProviders.isSystemProviderEnabled(path);
   2545         }
   2546 
   2547         // Backup/restore interface
   2548         @Override
   2549         public byte[] getBackupPayload(int user) {
   2550             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
   2551             //TODO: http://b/22388012
   2552             if (user != UserHandle.USER_SYSTEM) {
   2553                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
   2554                 return null;
   2555             }
   2556             synchronized(mPolicyFile) {
   2557                 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
   2558                 try {
   2559                     writePolicyXml(baos, true /*forBackup*/);
   2560                     return baos.toByteArray();
   2561                 } catch (IOException e) {
   2562                     Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
   2563                 }
   2564             }
   2565             return null;
   2566         }
   2567 
   2568         @Override
   2569         public void applyRestore(byte[] payload, int user) {
   2570             if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
   2571                     + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
   2572             if (payload == null) {
   2573                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
   2574                 return;
   2575             }
   2576             //TODO: http://b/22388012
   2577             if (user != UserHandle.USER_SYSTEM) {
   2578                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
   2579                 return;
   2580             }
   2581             synchronized(mPolicyFile) {
   2582                 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
   2583                 try {
   2584                     readPolicyXml(bais, true /*forRestore*/);
   2585                     savePolicyFile();
   2586                 } catch (NumberFormatException | XmlPullParserException | IOException e) {
   2587                     Slog.w(TAG, "applyRestore: error reading payload", e);
   2588                 }
   2589             }
   2590         }
   2591 
   2592         @Override
   2593         public boolean isNotificationPolicyAccessGranted(String pkg) {
   2594             return checkPolicyAccess(pkg);
   2595         }
   2596 
   2597         @Override
   2598         public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
   2599             enforceSystemOrSystemUIOrSamePackage(pkg,
   2600                     "request policy access status for another package");
   2601             return checkPolicyAccess(pkg);
   2602         }
   2603 
   2604         @Override
   2605         public String[] getPackagesRequestingNotificationPolicyAccess()
   2606                 throws RemoteException {
   2607             enforceSystemOrSystemUI("request policy access packages");
   2608             final long identity = Binder.clearCallingIdentity();
   2609             try {
   2610                 return mPolicyAccess.getRequestingPackages();
   2611             } finally {
   2612                 Binder.restoreCallingIdentity(identity);
   2613             }
   2614         }
   2615 
   2616         @Override
   2617         public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
   2618                 throws RemoteException {
   2619             enforceSystemOrSystemUI("grant notification policy access");
   2620             final long identity = Binder.clearCallingIdentity();
   2621             try {
   2622                 synchronized (mNotificationLock) {
   2623                     mPolicyAccess.put(pkg, granted);
   2624                 }
   2625             } finally {
   2626                 Binder.restoreCallingIdentity(identity);
   2627             }
   2628         }
   2629 
   2630         @Override
   2631         public Policy getNotificationPolicy(String pkg) {
   2632             enforcePolicyAccess(pkg, "getNotificationPolicy");
   2633             final long identity = Binder.clearCallingIdentity();
   2634             try {
   2635                 return mZenModeHelper.getNotificationPolicy();
   2636             } finally {
   2637                 Binder.restoreCallingIdentity(identity);
   2638             }
   2639         }
   2640 
   2641         @Override
   2642         public void setNotificationPolicy(String pkg, Policy policy) {
   2643             enforcePolicyAccess(pkg, "setNotificationPolicy");
   2644             final long identity = Binder.clearCallingIdentity();
   2645             try {
   2646                 mZenModeHelper.setNotificationPolicy(policy);
   2647             } finally {
   2648                 Binder.restoreCallingIdentity(identity);
   2649             }
   2650         }
   2651 
   2652         @Override
   2653         public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
   2654                 Adjustment adjustment) throws RemoteException {
   2655             final long identity = Binder.clearCallingIdentity();
   2656             try {
   2657                 synchronized (mNotificationLock) {
   2658                     mNotificationAssistants.checkServiceTokenLocked(token);
   2659                     int N = mEnqueuedNotifications.size();
   2660                     for (int i = 0; i < N; i++) {
   2661                         final NotificationRecord n = mEnqueuedNotifications.get(i);
   2662                         if (Objects.equals(adjustment.getKey(), n.getKey())
   2663                                 && Objects.equals(adjustment.getUser(), n.getUserId())) {
   2664                             applyAdjustment(n, adjustment);
   2665                             break;
   2666                         }
   2667                     }
   2668                 }
   2669             } finally {
   2670                 Binder.restoreCallingIdentity(identity);
   2671             }
   2672         }
   2673 
   2674         @Override
   2675         public void applyAdjustmentFromAssistant(INotificationListener token,
   2676                 Adjustment adjustment) throws RemoteException {
   2677             final long identity = Binder.clearCallingIdentity();
   2678             try {
   2679                 synchronized (mNotificationLock) {
   2680                     mNotificationAssistants.checkServiceTokenLocked(token);
   2681                     NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
   2682                     applyAdjustment(n, adjustment);
   2683                 }
   2684                 mRankingHandler.requestSort(true);
   2685             } finally {
   2686                 Binder.restoreCallingIdentity(identity);
   2687             }
   2688         }
   2689 
   2690         @Override
   2691         public void applyAdjustmentsFromAssistant(INotificationListener token,
   2692                 List<Adjustment> adjustments) throws RemoteException {
   2693 
   2694             final long identity = Binder.clearCallingIdentity();
   2695             try {
   2696                 synchronized (mNotificationLock) {
   2697                     mNotificationAssistants.checkServiceTokenLocked(token);
   2698                     for (Adjustment adjustment : adjustments) {
   2699                         NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
   2700                         applyAdjustment(n, adjustment);
   2701                     }
   2702                 }
   2703                 mRankingHandler.requestSort(true);
   2704             } finally {
   2705                 Binder.restoreCallingIdentity(identity);
   2706             }
   2707         }
   2708 
   2709         @Override
   2710         public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
   2711                 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
   2712             Preconditions.checkNotNull(channel);
   2713             Preconditions.checkNotNull(pkg);
   2714             Preconditions.checkNotNull(user);
   2715 
   2716             verifyPrivilegedListener(token, user);
   2717             updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
   2718         }
   2719 
   2720         @Override
   2721         public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
   2722                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
   2723             Preconditions.checkNotNull(pkg);
   2724             Preconditions.checkNotNull(user);
   2725             verifyPrivilegedListener(token, user);
   2726 
   2727             return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
   2728                     false /* includeDeleted */);
   2729         }
   2730 
   2731         @Override
   2732         public ParceledListSlice<NotificationChannelGroup>
   2733                 getNotificationChannelGroupsFromPrivilegedListener(
   2734                 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
   2735             Preconditions.checkNotNull(pkg);
   2736             Preconditions.checkNotNull(user);
   2737             verifyPrivilegedListener(token, user);
   2738 
   2739             List<NotificationChannelGroup> groups = new ArrayList<>();
   2740             groups.addAll(mRankingHelper.getNotificationChannelGroups(
   2741                     pkg, getUidForPackageAndUser(pkg, user)));
   2742             return new ParceledListSlice<>(groups);
   2743         }
   2744 
   2745         private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
   2746             ManagedServiceInfo info;
   2747             synchronized (mNotificationLock) {
   2748                 info = mListeners.checkServiceTokenLocked(token);
   2749             }
   2750             if (!hasCompanionDevice(info)) {
   2751                 throw new SecurityException(info + " does not have access");
   2752             }
   2753             if (!info.enabledAndUserMatches(user.getIdentifier())) {
   2754                 throw new SecurityException(info + " does not have access");
   2755             }
   2756         }
   2757 
   2758         private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
   2759             int uid = 0;
   2760             long identity = Binder.clearCallingIdentity();
   2761             try {
   2762                 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
   2763             } finally {
   2764                 Binder.restoreCallingIdentity(identity);
   2765             }
   2766             return uid;
   2767         }
   2768     };
   2769 
   2770     private void applyAdjustment(NotificationRecord n, Adjustment adjustment) {
   2771         if (n == null) {
   2772             return;
   2773         }
   2774         if (adjustment.getSignals() != null) {
   2775             Bundle.setDefusable(adjustment.getSignals(), true);
   2776             final ArrayList<String> people =
   2777                     adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
   2778             final ArrayList<SnoozeCriterion> snoozeCriterionList =
   2779                     adjustment.getSignals().getParcelableArrayList(Adjustment.KEY_SNOOZE_CRITERIA);
   2780             n.setPeopleOverride(people);
   2781             n.setSnoozeCriteria(snoozeCriterionList);
   2782         }
   2783     }
   2784 
   2785     @GuardedBy("mNotificationLock")
   2786     private void addAutogroupKeyLocked(String key) {
   2787         NotificationRecord n = mNotificationsByKey.get(key);
   2788         if (n == null) {
   2789             return;
   2790         }
   2791         n.setOverrideGroupKey(GroupHelper.AUTOGROUP_KEY);
   2792         EventLogTags.writeNotificationAutogrouped(key);
   2793     }
   2794 
   2795     @GuardedBy("mNotificationLock")
   2796     private void removeAutogroupKeyLocked(String key) {
   2797         NotificationRecord n = mNotificationsByKey.get(key);
   2798         if (n == null) {
   2799             return;
   2800         }
   2801         n.setOverrideGroupKey(null);
   2802         EventLogTags.writeNotificationUnautogrouped(key);
   2803     }
   2804 
   2805     // Clears the 'fake' auto-group summary.
   2806     @GuardedBy("mNotificationLock")
   2807     private void clearAutogroupSummaryLocked(int userId, String pkg) {
   2808         ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
   2809         if (summaries != null && summaries.containsKey(pkg)) {
   2810             // Clear summary.
   2811             final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
   2812             if (removed != null) {
   2813                 boolean wasPosted = removeFromNotificationListsLocked(removed);
   2814                 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted);
   2815             }
   2816         }
   2817     }
   2818 
   2819     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
   2820     private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
   2821         NotificationRecord summaryRecord = null;
   2822         synchronized (mNotificationLock) {
   2823             NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
   2824             if (notificationRecord == null) {
   2825                 // The notification could have been cancelled again already. A successive
   2826                 // adjustment will post a summary if needed.
   2827                 return;
   2828             }
   2829             final StatusBarNotification adjustedSbn = notificationRecord.sbn;
   2830             userId = adjustedSbn.getUser().getIdentifier();
   2831             ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
   2832             if (summaries == null) {
   2833                 summaries = new ArrayMap<>();
   2834             }
   2835             mAutobundledSummaries.put(userId, summaries);
   2836             if (!summaries.containsKey(pkg)) {
   2837                 // Add summary
   2838                 final ApplicationInfo appInfo =
   2839                        adjustedSbn.getNotification().extras.getParcelable(
   2840                                Notification.EXTRA_BUILDER_APPLICATION_INFO);
   2841                 final Bundle extras = new Bundle();
   2842                 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
   2843                 final String channelId = notificationRecord.getChannel().getId();
   2844                 final Notification summaryNotification =
   2845                         new Notification.Builder(getContext(), channelId)
   2846                                 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
   2847                                 .setGroupSummary(true)
   2848                                 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
   2849                                 .setGroup(GroupHelper.AUTOGROUP_KEY)
   2850                                 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
   2851                                 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
   2852                                 .setColor(adjustedSbn.getNotification().color)
   2853                                 .setLocalOnly(true)
   2854                                 .build();
   2855                 summaryNotification.extras.putAll(extras);
   2856                 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
   2857                 if (appIntent != null) {
   2858                     summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
   2859                             getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
   2860                 }
   2861                 final StatusBarNotification summarySbn =
   2862                         new StatusBarNotification(adjustedSbn.getPackageName(),
   2863                                 adjustedSbn.getOpPkg(),
   2864                                 Integer.MAX_VALUE,
   2865                                 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
   2866                                 adjustedSbn.getInitialPid(), summaryNotification,
   2867                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
   2868                                 System.currentTimeMillis());
   2869                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
   2870                         notificationRecord.getChannel());
   2871                 summaries.put(pkg, summarySbn.getKey());
   2872             }
   2873         }
   2874         if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
   2875                 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord)) {
   2876             mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
   2877         }
   2878     }
   2879 
   2880     private String disableNotificationEffects(NotificationRecord record) {
   2881         if (mDisableNotificationEffects) {
   2882             return "booleanState";
   2883         }
   2884         if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
   2885             return "listenerHints";
   2886         }
   2887         if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
   2888             return "callState";
   2889         }
   2890         return null;
   2891     };
   2892 
   2893     private void dumpJson(PrintWriter pw, DumpFilter filter) {
   2894         JSONObject dump = new JSONObject();
   2895         try {
   2896             dump.put("service", "Notification Manager");
   2897             dump.put("bans", mRankingHelper.dumpBansJson(filter));
   2898             dump.put("ranking", mRankingHelper.dumpJson(filter));
   2899             dump.put("stats", mUsageStats.dumpJson(filter));
   2900             dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
   2901         } catch (JSONException e) {
   2902             e.printStackTrace();
   2903         }
   2904         pw.println(dump);
   2905     }
   2906 
   2907     private void dumpProto(FileDescriptor fd, DumpFilter filter) {
   2908         final ProtoOutputStream proto = new ProtoOutputStream(fd);
   2909         synchronized (mNotificationLock) {
   2910             long records = proto.start(NotificationServiceDumpProto.RECORDS);
   2911             int N = mNotificationList.size();
   2912             if (N > 0) {
   2913                 for (int i = 0; i < N; i++) {
   2914                     final NotificationRecord nr = mNotificationList.get(i);
   2915                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
   2916                     nr.dump(proto, filter.redact);
   2917                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
   2918                 }
   2919             }
   2920             N = mEnqueuedNotifications.size();
   2921             if (N > 0) {
   2922                 for (int i = 0; i < N; i++) {
   2923                     final NotificationRecord nr = mEnqueuedNotifications.get(i);
   2924                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
   2925                     nr.dump(proto, filter.redact);
   2926                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
   2927                 }
   2928             }
   2929             List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
   2930             N = snoozed.size();
   2931             if (N > 0) {
   2932                 for (int i = 0; i < N; i++) {
   2933                     final NotificationRecord nr = snoozed.get(i);
   2934                     if (filter.filtered && !filter.matches(nr.sbn)) continue;
   2935                     nr.dump(proto, filter.redact);
   2936                     proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
   2937                 }
   2938             }
   2939             proto.end(records);
   2940         }
   2941 
   2942         long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
   2943         mZenModeHelper.dump(proto);
   2944         for (ComponentName suppressor : mEffectsSuppressors) {
   2945             proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
   2946         }
   2947         proto.end(zenLog);
   2948 
   2949         proto.flush();
   2950     }
   2951 
   2952     void dumpImpl(PrintWriter pw, DumpFilter filter) {
   2953         pw.print("Current Notification Manager state");
   2954         if (filter.filtered) {
   2955             pw.print(" (filtered to "); pw.print(filter); pw.print(")");
   2956         }
   2957         pw.println(':');
   2958         int N;
   2959         final boolean zenOnly = filter.filtered && filter.zen;
   2960 
   2961         if (!zenOnly) {
   2962             synchronized (mToastQueue) {
   2963                 N = mToastQueue.size();
   2964                 if (N > 0) {
   2965                     pw.println("  Toast Queue:");
   2966                     for (int i=0; i<N; i++) {
   2967                         mToastQueue.get(i).dump(pw, "    ", filter);
   2968                     }
   2969                     pw.println("  ");
   2970                 }
   2971             }
   2972         }
   2973 
   2974         synchronized (mNotificationLock) {
   2975             if (!zenOnly) {
   2976                 N = mNotificationList.size();
   2977                 if (N > 0) {
   2978                     pw.println("  Notification List:");
   2979                     for (int i=0; i<N; i++) {
   2980                         final NotificationRecord nr = mNotificationList.get(i);
   2981                         if (filter.filtered && !filter.matches(nr.sbn)) continue;
   2982                         nr.dump(pw, "    ", getContext(), filter.redact);
   2983                     }
   2984                     pw.println("  ");
   2985                 }
   2986 
   2987                 if (!filter.filtered) {
   2988                     N = mLights.size();
   2989                     if (N > 0) {
   2990                         pw.println("  Lights List:");
   2991                         for (int i=0; i<N; i++) {
   2992                             if (i == N - 1) {
   2993                                 pw.print("  > ");
   2994                             } else {
   2995                                 pw.print("    ");
   2996                             }
   2997                             pw.println(mLights.get(i));
   2998                         }
   2999                         pw.println("  ");
   3000                     }
   3001                     pw.println("  mUseAttentionLight=" + mUseAttentionLight);
   3002                     pw.println("  mNotificationPulseEnabled=" + mNotificationPulseEnabled);
   3003                     pw.println("  mSoundNotificationKey=" + mSoundNotificationKey);
   3004                     pw.println("  mVibrateNotificationKey=" + mVibrateNotificationKey);
   3005                     pw.println("  mDisableNotificationEffects=" + mDisableNotificationEffects);
   3006                     pw.println("  mCallState=" + callStateToString(mCallState));
   3007                     pw.println("  mSystemReady=" + mSystemReady);
   3008                     pw.println("  mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
   3009                 }
   3010                 pw.println("  mArchive=" + mArchive.toString());
   3011                 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
   3012                 int j=0;
   3013                 while (iter.hasNext()) {
   3014                     final StatusBarNotification sbn = iter.next();
   3015                     if (filter != null && !filter.matches(sbn)) continue;
   3016                     pw.println("    " + sbn);
   3017                     if (++j >= 5) {
   3018                         if (iter.hasNext()) pw.println("    ...");
   3019                         break;
   3020                     }
   3021                 }
   3022 
   3023                 if (!zenOnly) {
   3024                     N = mEnqueuedNotifications.size();
   3025                     if (N > 0) {
   3026                         pw.println("  Enqueued Notification List:");
   3027                         for (int i = 0; i < N; i++) {
   3028                             final NotificationRecord nr = mEnqueuedNotifications.get(i);
   3029                             if (filter.filtered && !filter.matches(nr.sbn)) continue;
   3030                             nr.dump(pw, "    ", getContext(), filter.redact);
   3031                         }
   3032                         pw.println("  ");
   3033                     }
   3034 
   3035                     mSnoozeHelper.dump(pw, filter);
   3036                 }
   3037             }
   3038 
   3039             if (!zenOnly) {
   3040                 pw.println("\n  Ranking Config:");
   3041                 mRankingHelper.dump(pw, "    ", filter);
   3042 
   3043                 pw.println("\n  Notification listeners:");
   3044                 mListeners.dump(pw, filter);
   3045                 pw.print("    mListenerHints: "); pw.println(mListenerHints);
   3046                 pw.print("    mListenersDisablingEffects: (");
   3047                 N = mListenersDisablingEffects.size();
   3048                 for (int i = 0; i < N; i++) {
   3049                     final int hint = mListenersDisablingEffects.keyAt(i);
   3050                     if (i > 0) pw.print(';');
   3051                     pw.print("hint[" + hint + "]:");
   3052 
   3053                     final ArraySet<ManagedServiceInfo> listeners =
   3054                             mListenersDisablingEffects.valueAt(i);
   3055                     final int listenerSize = listeners.size();
   3056 
   3057                     for (int j = 0; j < listenerSize; j++) {
   3058                         if (i > 0) pw.print(',');
   3059                         final ManagedServiceInfo listener = listeners.valueAt(i);
   3060                         pw.print(listener.component);
   3061                     }
   3062                 }
   3063                 pw.println(')');
   3064                 pw.println("\n  Notification assistant services:");
   3065                 mNotificationAssistants.dump(pw, filter);
   3066             }
   3067 
   3068             if (!filter.filtered || zenOnly) {
   3069                 pw.println("\n  Zen Mode:");
   3070                 pw.print("    mInterruptionFilter="); pw.println(mInterruptionFilter);
   3071                 mZenModeHelper.dump(pw, "    ");
   3072 
   3073                 pw.println("\n  Zen Log:");
   3074                 ZenLog.dump(pw, "    ");
   3075             }
   3076 
   3077             pw.println("\n  Policy access:");
   3078             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
   3079 
   3080             pw.println("\n  Condition providers:");
   3081             mConditionProviders.dump(pw, filter);
   3082 
   3083             pw.println("\n  Group summaries:");
   3084             for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
   3085                 NotificationRecord r = entry.getValue();
   3086                 pw.println("    " + entry.getKey() + " -> " + r.getKey());
   3087                 if (mNotificationsByKey.get(r.getKey()) != r) {
   3088                     pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
   3089                     r.dump(pw, "      ", getContext(), filter.redact);
   3090                 }
   3091             }
   3092 
   3093             if (!zenOnly) {
   3094                 pw.println("\n  Usage Stats:");
   3095                 mUsageStats.dump(pw, "    ", filter);
   3096             }
   3097         }
   3098     }
   3099 
   3100     /**
   3101      * The private API only accessible to the system process.
   3102      */
   3103     private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
   3104         @Override
   3105         public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
   3106                 String tag, int id, Notification notification, int userId) {
   3107             enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
   3108                     userId);
   3109         }
   3110 
   3111         @Override
   3112         public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
   3113                 int userId) {
   3114             checkCallerIsSystem();
   3115             mHandler.post(new Runnable() {
   3116                 @Override
   3117                 public void run() {
   3118                     synchronized (mNotificationLock) {
   3119                         removeForegroundServiceFlagByListLocked(
   3120                                 mEnqueuedNotifications, pkg, notificationId, userId);
   3121                         removeForegroundServiceFlagByListLocked(
   3122                                 mNotificationList, pkg, notificationId, userId);
   3123                     }
   3124                 }
   3125             });
   3126         }
   3127 
   3128         @GuardedBy("mNotificationLock")
   3129         private void removeForegroundServiceFlagByListLocked(
   3130                 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
   3131                 int userId) {
   3132             NotificationRecord r = findNotificationByListLocked(
   3133                     notificationList, pkg, null, notificationId, userId);
   3134             if (r == null) {
   3135                 return;
   3136             }
   3137             StatusBarNotification sbn = r.sbn;
   3138             // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
   3139             // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
   3140             // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
   3141             // initially *and* force remove FLAG_FOREGROUND_SERVICE.
   3142             sbn.getNotification().flags =
   3143                     (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
   3144             mRankingHelper.sort(mNotificationList);
   3145             mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
   3146             mGroupHelper.onNotificationPosted(sbn);
   3147         }
   3148     };
   3149 
   3150     void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
   3151             final int callingPid, final String tag, final int id, final Notification notification,
   3152             int incomingUserId) {
   3153         if (DBG) {
   3154             Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
   3155                     + " notification=" + notification);
   3156         }
   3157         checkCallerIsSystemOrSameApp(pkg);
   3158 
   3159         final int userId = ActivityManager.handleIncomingUser(callingPid,
   3160                 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
   3161         final UserHandle user = new UserHandle(userId);
   3162 
   3163         if (pkg == null || notification == null) {
   3164             throw new IllegalArgumentException("null not allowed: pkg=" + pkg
   3165                     + " id=" + id + " notification=" + notification);
   3166         }
   3167 
   3168         // The system can post notifications for any package, let us resolve that.
   3169         final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
   3170 
   3171         // Fix the notification as best we can.
   3172         try {
   3173             final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
   3174                     pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
   3175                     (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
   3176             Notification.addFieldsFromContext(ai, notification);
   3177         } catch (NameNotFoundException e) {
   3178             Slog.e(TAG, "Cannot create a context for sending app", e);
   3179             return;
   3180         }
   3181 
   3182         mUsageStats.registerEnqueuedByApp(pkg);
   3183 
   3184         // setup local book-keeping
   3185         String channelId = notification.getChannelId();
   3186         if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
   3187             channelId = (new Notification.TvExtender(notification)).getChannelId();
   3188         }
   3189         final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
   3190                 notificationUid, channelId, false /* includeDeleted */);
   3191         if (channel == null) {
   3192             final String noChannelStr = "No Channel found for "
   3193                     + "pkg=" + pkg
   3194                     + ", channelId=" + channelId
   3195                     + ", id=" + id
   3196                     + ", tag=" + tag
   3197                     + ", opPkg=" + opPkg
   3198                     + ", callingUid=" + callingUid
   3199                     + ", userId=" + userId
   3200                     + ", incomingUserId=" + incomingUserId
   3201                     + ", notificationUid=" + notificationUid
   3202                     + ", notification=" + notification;
   3203             Log.e(TAG, noChannelStr);
   3204             doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
   3205                     "Failed to post notification on channel \"" + channelId + "\"\n" +
   3206                     "See log for more details");
   3207             return;
   3208         }
   3209 
   3210         final StatusBarNotification n = new StatusBarNotification(
   3211                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
   3212                 user, null, System.currentTimeMillis());
   3213         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
   3214 
   3215         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r)) {
   3216             return;
   3217         }
   3218 
   3219         // Whitelist pending intents.
   3220         if (notification.allPendingIntents != null) {
   3221             final int intentCount = notification.allPendingIntents.size();
   3222             if (intentCount > 0) {
   3223                 final ActivityManagerInternal am = LocalServices
   3224                         .getService(ActivityManagerInternal.class);
   3225                 final long duration = LocalServices.getService(
   3226                         DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
   3227                 for (int i = 0; i < intentCount; i++) {
   3228                     PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
   3229                     if (pendingIntent != null) {
   3230                         am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
   3231                                 WHITELIST_TOKEN, duration);
   3232                     }
   3233                 }
   3234             }
   3235         }
   3236 
   3237         mHandler.post(new EnqueueNotificationRunnable(userId, r));
   3238     }
   3239 
   3240     private void doChannelWarningToast(CharSequence toastText) {
   3241         final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
   3242         final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
   3243                 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
   3244         if (warningEnabled) {
   3245             Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
   3246                     Toast.LENGTH_SHORT);
   3247             toast.show();
   3248         }
   3249     }
   3250 
   3251     private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
   3252         // The system can post notifications on behalf of any package it wants
   3253         if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
   3254             try {
   3255                 return getContext().getPackageManager()
   3256                         .getPackageUidAsUser(opPackageName, userId);
   3257             } catch (NameNotFoundException e) {
   3258                 /* ignore */
   3259             }
   3260         }
   3261         return callingUid;
   3262     }
   3263 
   3264     /**
   3265      * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
   3266      *
   3267      * Has side effects.
   3268      */
   3269     private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
   3270             NotificationRecord r) {
   3271         final String pkg = r.sbn.getPackageName();
   3272         final boolean isSystemNotification =
   3273                 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
   3274         final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
   3275 
   3276         // Limit the number of notifications that any given package except the android
   3277         // package or a registered listener can enqueue.  Prevents DOS attacks and deals with leaks.
   3278         if (!isSystemNotification && !isNotificationFromListener) {
   3279             synchronized (mNotificationLock) {
   3280                 if (mNotificationsByKey.get(r.sbn.getKey()) != null) {
   3281                     // this is an update, rate limit updates only
   3282                     final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
   3283                     if (appEnqueueRate > mMaxPackageEnqueueRate) {
   3284                         mUsageStats.registerOverRateQuota(pkg);
   3285                         final long now = SystemClock.elapsedRealtime();
   3286                         if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
   3287                             Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
   3288                                     + ". Shedding events. package=" + pkg);
   3289                             mLastOverRateLogTime = now;
   3290                         }
   3291                         return false;
   3292                     }
   3293                 } else if (isCallerInstantApp(pkg)) {
   3294                     // Ephemeral apps have some special constraints for notifications.
   3295                     // They are not allowed to create new notifications however they are allowed to
   3296                     // update notifications created by the system (e.g. a foreground service
   3297                     // notification).
   3298                     throw new SecurityException("Instant app " + pkg
   3299                             + " cannot create notifications");
   3300                 }
   3301 
   3302                 int count = 0;
   3303                 final int N = mNotificationList.size();
   3304                 for (int i=0; i<N; i++) {
   3305                     final NotificationRecord existing = mNotificationList.get(i);
   3306                     if (existing.sbn.getPackageName().equals(pkg)
   3307                             && existing.sbn.getUserId() == userId) {
   3308                         if (existing.sbn.getId() == id
   3309                                 && TextUtils.equals(existing.sbn.getTag(), tag)) {
   3310                             break;  // Allow updating existing notification
   3311                         }
   3312                         count++;
   3313                         if (count >= MAX_PACKAGE_NOTIFICATIONS) {
   3314                             mUsageStats.registerOverCountQuota(pkg);
   3315                             Slog.e(TAG, "Package has already posted " + count
   3316                                     + " notifications.  Not showing more.  package=" + pkg);
   3317                             return false;
   3318                         }
   3319                     }
   3320                 }
   3321             }
   3322         }
   3323 
   3324         // snoozed apps
   3325         if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
   3326             MetricsLogger.action(r.getLogMaker()
   3327                     .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
   3328                     .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
   3329             if (DBG) {
   3330                 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
   3331             }
   3332             mSnoozeHelper.update(userId, r);
   3333             savePolicyFile();
   3334             return false;
   3335         }
   3336 
   3337 
   3338         // blocked apps
   3339         if (isBlocked(r, mUsageStats)) {
   3340             return false;
   3341         }
   3342 
   3343         return true;
   3344     }
   3345 
   3346     protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
   3347         final String pkg = r.sbn.getPackageName();
   3348         final int callingUid = r.sbn.getUid();
   3349 
   3350         final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
   3351         if (isPackageSuspended) {
   3352             Slog.e(TAG, "Suppressing notification from package due to package "
   3353                     + "suspended by administrator.");
   3354             usageStats.registerSuspendedByAdmin(r);
   3355             return isPackageSuspended;
   3356         }
   3357 
   3358         final boolean isBlocked =
   3359                 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
   3360                 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
   3361         if (isBlocked) {
   3362             Slog.e(TAG, "Suppressing notification from package by user request.");
   3363             usageStats.registerBlocked(r);
   3364         }
   3365         return isBlocked;
   3366     }
   3367 
   3368     protected class SnoozeNotificationRunnable implements Runnable {
   3369         private final String mKey;
   3370         private final long mDuration;
   3371         private final String mSnoozeCriterionId;
   3372 
   3373         SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
   3374             mKey = key;
   3375             mDuration = duration;
   3376             mSnoozeCriterionId = snoozeCriterionId;
   3377         }
   3378 
   3379         @Override
   3380         public void run() {
   3381             synchronized (mNotificationLock) {
   3382                 final NotificationRecord r = findNotificationByKeyLocked(mKey);
   3383                 if (r != null) {
   3384                     snoozeLocked(r);
   3385                 }
   3386             }
   3387         }
   3388 
   3389         @GuardedBy("mNotificationLock")
   3390         void snoozeLocked(NotificationRecord r) {
   3391             if (r.sbn.isGroup()) {
   3392                 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
   3393                         r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
   3394                 if (r.getNotification().isGroupSummary()) {
   3395                     // snooze summary and all children
   3396                     for (int i = 0; i < groupNotifications.size(); i++) {
   3397                         snoozeNotificationLocked(groupNotifications.get(i));
   3398                     }
   3399                 } else {
   3400                     // if there is a valid summary for this group, and we are snoozing the only
   3401                     // child, also snooze the summary
   3402                     if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
   3403                         if (groupNotifications.size() != 2) {
   3404                             snoozeNotificationLocked(r);
   3405                         } else {
   3406                             // snooze summary and the one child
   3407                             for (int i = 0; i < groupNotifications.size(); i++) {
   3408                                 snoozeNotificationLocked(groupNotifications.get(i));
   3409                             }
   3410                         }
   3411                     } else {
   3412                         snoozeNotificationLocked(r);
   3413                     }
   3414                 }
   3415             } else {
   3416                 // just snooze the one notification
   3417                 snoozeNotificationLocked(r);
   3418             }
   3419         }
   3420 
   3421         @GuardedBy("mNotificationLock")
   3422         void snoozeNotificationLocked(NotificationRecord r) {
   3423             MetricsLogger.action(r.getLogMaker()
   3424                     .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
   3425                     .setType(MetricsEvent.TYPE_CLOSE)
   3426                     .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
   3427                             mSnoozeCriterionId == null ? 0 : 1));
   3428             boolean wasPosted = removeFromNotificationListsLocked(r);
   3429             cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted);
   3430             updateLightsLocked();
   3431             if (mSnoozeCriterionId != null) {
   3432                 mNotificationAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
   3433                 mSnoozeHelper.snooze(r);
   3434             } else {
   3435                 mSnoozeHelper.snooze(r, mDuration);
   3436             }
   3437             savePolicyFile();
   3438         }
   3439     }
   3440 
   3441     protected class EnqueueNotificationRunnable implements Runnable {
   3442         private final NotificationRecord r;
   3443         private final int userId;
   3444 
   3445         EnqueueNotificationRunnable(int userId, NotificationRecord r) {
   3446             this.userId = userId;
   3447             this.r = r;
   3448         };
   3449 
   3450         @Override
   3451         public void run() {
   3452             synchronized (mNotificationLock) {
   3453                 mEnqueuedNotifications.add(r);
   3454                 scheduleTimeoutLocked(r);
   3455 
   3456                 final StatusBarNotification n = r.sbn;
   3457                 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
   3458                 NotificationRecord old = mNotificationsByKey.get(n.getKey());
   3459                 if (old != null) {
   3460                     // Retain ranking information from previous record
   3461                     r.copyRankingInformation(old);
   3462                 }
   3463 
   3464                 final int callingUid = n.getUid();
   3465                 final int callingPid = n.getInitialPid();
   3466                 final Notification notification = n.getNotification();
   3467                 final String pkg = n.getPackageName();
   3468                 final int id = n.getId();
   3469                 final String tag = n.getTag();
   3470 
   3471                 // Handle grouped notifications and bail out early if we
   3472                 // can to avoid extracting signals.
   3473                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
   3474 
   3475                 // if this is a group child, unsnooze parent summary
   3476                 if (n.isGroup() && notification.isGroupChild()) {
   3477                     mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
   3478                 }
   3479 
   3480                 // This conditional is a dirty hack to limit the logging done on
   3481                 //     behalf of the download manager without affecting other apps.
   3482                 if (!pkg.equals("com.android.providers.downloads")
   3483                         || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
   3484                     int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
   3485                     if (old != null) {
   3486                         enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
   3487                     }
   3488                     EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
   3489                             pkg, id, tag, userId, notification.toString(),
   3490                             enqueueStatus);
   3491                 }
   3492 
   3493                 mRankingHelper.extractSignals(r);
   3494 
   3495                 // tell the assistant service about the notification
   3496                 if (mNotificationAssistants.isEnabled()) {
   3497                     mNotificationAssistants.onNotificationEnqueued(r);
   3498                     mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
   3499                             DELAY_FOR_ASSISTANT_TIME);
   3500                 } else {
   3501                     mHandler.post(new PostNotificationRunnable(r.getKey()));
   3502                 }
   3503             }
   3504         }
   3505     }
   3506 
   3507     protected class PostNotificationRunnable implements Runnable {
   3508         private final String key;
   3509 
   3510         PostNotificationRunnable(String key) {
   3511             this.key = key;
   3512         }
   3513 
   3514         @Override
   3515         public void run() {
   3516             synchronized (mNotificationLock) {
   3517                 try {
   3518                     NotificationRecord r = null;
   3519                     int N = mEnqueuedNotifications.size();
   3520                     for (int i = 0; i < N; i++) {
   3521                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
   3522                         if (Objects.equals(key, enqueued.getKey())) {
   3523                             r = enqueued;
   3524                             break;
   3525                         }
   3526                     }
   3527                     if (r == null) {
   3528                         Slog.i(TAG, "Cannot find enqueued record for key: " + key);
   3529                         return;
   3530                     }
   3531                     NotificationRecord old = mNotificationsByKey.get(key);
   3532                     final StatusBarNotification n = r.sbn;
   3533                     final Notification notification = n.getNotification();
   3534                     int index = indexOfNotificationLocked(n.getKey());
   3535                     if (index < 0) {
   3536                         mNotificationList.add(r);
   3537                         mUsageStats.registerPostedByApp(r);
   3538                     } else {
   3539                         old = mNotificationList.get(index);
   3540                         mNotificationList.set(index, r);
   3541                         mUsageStats.registerUpdatedByApp(r, old);
   3542                         // Make sure we don't lose the foreground service state.
   3543                         notification.flags |=
   3544                                 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
   3545                         r.isUpdate = true;
   3546                     }
   3547 
   3548                     mNotificationsByKey.put(n.getKey(), r);
   3549 
   3550                     // Ensure if this is a foreground service that the proper additional
   3551                     // flags are set.
   3552                     if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
   3553                         notification.flags |= Notification.FLAG_ONGOING_EVENT
   3554                                 | Notification.FLAG_NO_CLEAR;
   3555                     }
   3556 
   3557                     applyZenModeLocked(r);
   3558                     mRankingHelper.sort(mNotificationList);
   3559 
   3560                     if (notification.getSmallIcon() != null) {
   3561                         StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
   3562                         mListeners.notifyPostedLocked(n, oldSbn);
   3563                         mHandler.post(new Runnable() {
   3564                             @Override
   3565                             public void run() {
   3566                                 mGroupHelper.onNotificationPosted(n);
   3567                             }
   3568                         });
   3569                     } else {
   3570                         Slog.e(TAG, "Not posting notification without small icon: " + notification);
   3571                         if (old != null && !old.isCanceled) {
   3572                             mListeners.notifyRemovedLocked(n,
   3573                                     NotificationListenerService.REASON_ERROR);
   3574                             mHandler.post(new Runnable() {
   3575                                 @Override
   3576                                 public void run() {
   3577                                     mGroupHelper.onNotificationRemoved(n);
   3578                                 }
   3579                             });
   3580                         }
   3581                         // ATTENTION: in a future release we will bail out here
   3582                         // so that we do not play sounds, show lights, etc. for invalid
   3583                         // notifications
   3584                         Slog.e(TAG, "WARNING: In a future release this will crash the app: "
   3585                                 + n.getPackageName());
   3586                     }
   3587 
   3588                     buzzBeepBlinkLocked(r);
   3589                 } finally {
   3590                     int N = mEnqueuedNotifications.size();
   3591                     for (int i = 0; i < N; i++) {
   3592                         final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
   3593                         if (Objects.equals(key, enqueued.getKey())) {
   3594                             mEnqueuedNotifications.remove(i);
   3595                             break;
   3596                         }
   3597                     }
   3598                 }
   3599             }
   3600         }
   3601     }
   3602 
   3603     /**
   3604      * Ensures that grouped notification receive their special treatment.
   3605      *
   3606      * <p>Cancels group children if the new notification causes a group to lose
   3607      * its summary.</p>
   3608      *
   3609      * <p>Updates mSummaryByGroupKey.</p>
   3610      */
   3611     @GuardedBy("mNotificationLock")
   3612     private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
   3613             int callingUid, int callingPid) {
   3614         StatusBarNotification sbn = r.sbn;
   3615         Notification n = sbn.getNotification();
   3616         if (n.isGroupSummary() && !sbn.isAppGroup())  {
   3617             // notifications without a group shouldn't be a summary, otherwise autobundling can
   3618             // lead to bugs
   3619             n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
   3620         }
   3621 
   3622         String group = sbn.getGroupKey();
   3623         boolean isSummary = n.isGroupSummary();
   3624 
   3625         Notification oldN = old != null ? old.sbn.getNotification() : null;
   3626         String oldGroup = old != null ? old.sbn.getGroupKey() : null;
   3627         boolean oldIsSummary = old != null && oldN.isGroupSummary();
   3628 
   3629         if (oldIsSummary) {
   3630             NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
   3631             if (removedSummary != old) {
   3632                 String removedKey =
   3633                         removedSummary != null ? removedSummary.getKey() : "<null>";
   3634                 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
   3635                         ", removed=" + removedKey);
   3636             }
   3637         }
   3638         if (isSummary) {
   3639             mSummaryByGroupKey.put(group, r);
   3640         }
   3641 
   3642         // Clear out group children of the old notification if the update
   3643         // causes the group summary to go away. This happens when the old
   3644         // notification was a summary and the new one isn't, or when the old
   3645         // notification was a summary and its group key changed.
   3646         if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
   3647             cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */);
   3648         }
   3649     }
   3650 
   3651     @VisibleForTesting
   3652     @GuardedBy("mNotificationLock")
   3653     void scheduleTimeoutLocked(NotificationRecord record) {
   3654         if (record.getNotification().getTimeoutAfter() > 0) {
   3655             final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
   3656                     REQUEST_CODE_TIMEOUT,
   3657                     new Intent(ACTION_NOTIFICATION_TIMEOUT)
   3658                             .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
   3659                                     .appendPath(record.getKey()).build())
   3660                             .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
   3661                             .putExtra(EXTRA_KEY, record.getKey()),
   3662                     PendingIntent.FLAG_UPDATE_CURRENT);
   3663             mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
   3664                     SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
   3665         }
   3666     }
   3667 
   3668     @VisibleForTesting
   3669     @GuardedBy("mNotificationLock")
   3670     void buzzBeepBlinkLocked(NotificationRecord record) {
   3671         boolean buzz = false;
   3672         boolean beep = false;
   3673         boolean blink = false;
   3674 
   3675         final Notification notification = record.sbn.getNotification();
   3676         final String key = record.getKey();
   3677 
   3678         // Should this notification make noise, vibe, or use the LED?
   3679         final boolean aboveThreshold =
   3680                 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
   3681         final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
   3682         if (DBG)
   3683             Slog.v(TAG,
   3684                     "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
   3685                             " intercept=" + record.isIntercepted()
   3686             );
   3687 
   3688         // If we're not supposed to beep, vibrate, etc. then don't.
   3689         final String disableEffects = disableNotificationEffects(record);
   3690         if (disableEffects != null) {
   3691             ZenLog.traceDisableEffects(record, disableEffects);
   3692         }
   3693 
   3694         // Remember if this notification already owns the notification channels.
   3695         boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
   3696         boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
   3697         // These are set inside the conditional if the notification is allowed to make noise.
   3698         boolean hasValidVibrate = false;
   3699         boolean hasValidSound = false;
   3700 
   3701         if (isNotificationForCurrentUser(record)) {
   3702             // If the notification will appear in the status bar, it should send an accessibility
   3703             // event
   3704             if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
   3705                 sendAccessibilityEvent(notification, record.sbn.getPackageName());
   3706             }
   3707 
   3708             if (disableEffects == null
   3709                     && canInterrupt
   3710                     && mSystemReady
   3711                     && mAudioManager != null) {
   3712                 if (DBG) Slog.v(TAG, "Interrupting!");
   3713                 Uri soundUri = record.getSound();
   3714                 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
   3715                 long[] vibration = record.getVibration();
   3716                 // Demote sound to vibration if vibration missing & phone in vibration mode.
   3717                 if (vibration == null
   3718                         && hasValidSound
   3719                         && (mAudioManager.getRingerModeInternal()
   3720                         == AudioManager.RINGER_MODE_VIBRATE)) {
   3721                     vibration = mFallbackVibrationPattern;
   3722                 }
   3723                 hasValidVibrate = vibration != null;
   3724 
   3725                 if (!shouldMuteNotificationLocked(record)) {
   3726                     if (hasValidSound) {
   3727                         mSoundNotificationKey = key;
   3728                         if (mInCall) {
   3729                             playInCallNotification();
   3730                             beep = true;
   3731                         } else {
   3732                             beep = playSound(record, soundUri);
   3733                         }
   3734                     }
   3735 
   3736                     final boolean ringerModeSilent =
   3737                             mAudioManager.getRingerModeInternal()
   3738                                     == AudioManager.RINGER_MODE_SILENT;
   3739                     if (!mInCall && hasValidVibrate && !ringerModeSilent) {
   3740                         mVibrateNotificationKey = key;
   3741 
   3742                         buzz = playVibration(record, vibration, hasValidSound);
   3743                     }
   3744                 }
   3745             }
   3746         }
   3747         // If a notification is updated to remove the actively playing sound or vibrate,
   3748         // cancel that feedback now
   3749         if (wasBeep && !hasValidSound) {
   3750             clearSoundLocked();
   3751         }
   3752         if (wasBuzz && !hasValidVibrate) {
   3753             clearVibrateLocked();
   3754         }
   3755 
   3756         // light
   3757         // release the light
   3758         boolean wasShowLights = mLights.remove(key);
   3759         if (record.getLight() != null && aboveThreshold
   3760                 && ((record.getSuppressedVisualEffects()
   3761                 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
   3762             mLights.add(key);
   3763             updateLightsLocked();
   3764             if (mUseAttentionLight) {
   3765                 mAttentionLight.pulse();
   3766             }
   3767             blink = true;
   3768         } else if (wasShowLights) {
   3769             updateLightsLocked();
   3770         }
   3771         if (buzz || beep || blink) {
   3772             MetricsLogger.action(record.getLogMaker()
   3773                     .setCategory(MetricsEvent.NOTIFICATION_ALERT)
   3774                     .setType(MetricsEvent.TYPE_OPEN)
   3775                     .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
   3776             EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
   3777         }
   3778     }
   3779 
   3780     @GuardedBy("mNotificationLock")
   3781     boolean shouldMuteNotificationLocked(final NotificationRecord record) {
   3782         final Notification notification = record.getNotification();
   3783         if(record.isUpdate
   3784                 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
   3785             return true;
   3786         }
   3787         if (record.sbn.isGroup()) {
   3788             return notification.suppressAlertingDueToGrouping();
   3789         }
   3790         return false;
   3791     }
   3792 
   3793     private boolean playSound(final NotificationRecord record, Uri soundUri) {
   3794         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
   3795         // do not play notifications if there is a user of exclusive audio focus
   3796         // or the device is in vibrate mode
   3797         if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
   3798                 != AudioManager.RINGER_MODE_VIBRATE) {
   3799             final long identity = Binder.clearCallingIdentity();
   3800             try {
   3801                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
   3802                 if (player != null) {
   3803                     if (DBG) Slog.v(TAG, "Playing sound " + soundUri
   3804                             + " with attributes " + record.getAudioAttributes());
   3805                     player.playAsync(soundUri, record.sbn.getUser(), looping,
   3806                             record.getAudioAttributes());
   3807                     return true;
   3808                 }
   3809             } catch (RemoteException e) {
   3810             } finally {
   3811                 Binder.restoreCallingIdentity(identity);
   3812             }
   3813         }
   3814         return false;
   3815     }
   3816 
   3817     private boolean playVibration(final NotificationRecord record, long[] vibration,
   3818             boolean delayVibForSound) {
   3819         // Escalate privileges so we can use the vibrator even if the
   3820         // notifying app does not have the VIBRATE permission.
   3821         long identity = Binder.clearCallingIdentity();
   3822         try {
   3823             final VibrationEffect effect;
   3824             try {
   3825                 final boolean insistent =
   3826                         (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
   3827                 effect = VibrationEffect.createWaveform(
   3828                         vibration, insistent ? 0 : -1 /*repeatIndex*/);
   3829             } catch (IllegalArgumentException e) {
   3830                 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
   3831                         Arrays.toString(vibration));
   3832                 return false;
   3833             }
   3834             if (delayVibForSound) {
   3835                 new Thread(() -> {
   3836                     // delay the vibration by the same amount as the notification sound
   3837                     final int waitMs = mAudioManager.getFocusRampTimeMs(
   3838                             AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
   3839                             record.getAudioAttributes());
   3840                     if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
   3841                     try {
   3842                         Thread.sleep(waitMs);
   3843                     } catch (InterruptedException e) { }
   3844                     mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
   3845                             effect, record.getAudioAttributes());
   3846                 }).start();
   3847             } else {
   3848                 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
   3849                         effect, record.getAudioAttributes());
   3850             }
   3851             return true;
   3852         } finally{
   3853             Binder.restoreCallingIdentity(identity);
   3854         }
   3855     }
   3856 
   3857     private boolean isNotificationForCurrentUser(NotificationRecord record) {
   3858         final int currentUser;
   3859         final long token = Binder.clearCallingIdentity();
   3860         try {
   3861             currentUser = ActivityManager.getCurrentUser();
   3862         } finally {
   3863             Binder.restoreCallingIdentity(token);
   3864         }
   3865         return (record.getUserId() == UserHandle.USER_ALL ||
   3866                 record.getUserId() == currentUser ||
   3867                 mUserProfiles.isCurrentProfile(record.getUserId()));
   3868     }
   3869 
   3870     private void playInCallNotification() {
   3871         new Thread() {
   3872             @Override
   3873             public void run() {
   3874                 // If toneGenerator creation fails, just continue the call
   3875                 // without playing the notification sound.
   3876                 try {
   3877                     synchronized (mInCallToneGeneratorLock) {
   3878                         if (mInCallToneGenerator != null) {
   3879                             // limit this tone to 1 second; BEEP2 should in fact be much shorter
   3880                             mInCallToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2, 1000);
   3881                         }
   3882                     }
   3883                 } catch (RuntimeException e) {
   3884                     Log.w(TAG, "Exception from ToneGenerator: " + e);
   3885                 }
   3886             }
   3887         }.start();
   3888     }
   3889 
   3890     @GuardedBy("mToastQueue")
   3891     void showNextToastLocked() {
   3892         ToastRecord record = mToastQueue.get(0);
   3893         while (record != null) {
   3894             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
   3895             try {
   3896                 record.callback.show(record.token);
   3897                 scheduleTimeoutLocked(record);
   3898                 return;
   3899             } catch (RemoteException e) {
   3900                 Slog.w(TAG, "Object died trying to show notification " + record.callback
   3901                         + " in package " + record.pkg);
   3902                 // remove it from the list and let the process die
   3903                 int index = mToastQueue.indexOf(record);
   3904                 if (index >= 0) {
   3905                     mToastQueue.remove(index);
   3906                 }
   3907                 keepProcessAliveIfNeededLocked(record.pid);
   3908                 if (mToastQueue.size() > 0) {
   3909                     record = mToastQueue.get(0);
   3910                 } else {
   3911                     record = null;
   3912                 }
   3913             }
   3914         }
   3915     }
   3916 
   3917     @GuardedBy("mToastQueue")
   3918     void cancelToastLocked(int index) {
   3919         ToastRecord record = mToastQueue.get(index);
   3920         try {
   3921             record.callback.hide();
   3922         } catch (RemoteException e) {
   3923             Slog.w(TAG, "Object died trying to hide notification " + record.callback
   3924                     + " in package " + record.pkg);
   3925             // don't worry about this, we're about to remove it from
   3926             // the list anyway
   3927         }
   3928 
   3929         ToastRecord lastToast = mToastQueue.remove(index);
   3930         mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
   3931 
   3932         keepProcessAliveIfNeededLocked(record.pid);
   3933         if (mToastQueue.size() > 0) {
   3934             // Show the next one. If the callback fails, this will remove
   3935             // it from the list, so don't assume that the list hasn't changed
   3936             // after this point.
   3937             showNextToastLocked();
   3938         }
   3939     }
   3940 
   3941     @GuardedBy("mToastQueue")
   3942     private void scheduleTimeoutLocked(ToastRecord r)
   3943     {
   3944         mHandler.removeCallbacksAndMessages(r);
   3945         Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
   3946         long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
   3947         mHandler.sendMessageDelayed(m, delay);
   3948     }
   3949 
   3950     private void handleTimeout(ToastRecord record)
   3951     {
   3952         if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
   3953         synchronized (mToastQueue) {
   3954             int index = indexOfToastLocked(record.pkg, record.callback);
   3955             if (index >= 0) {
   3956                 cancelToastLocked(index);
   3957             }
   3958         }
   3959     }
   3960 
   3961     @GuardedBy("mToastQueue")
   3962     int indexOfToastLocked(String pkg, ITransientNotification callback)
   3963     {
   3964         IBinder cbak = callback.asBinder();
   3965         ArrayList<ToastRecord> list = mToastQueue;
   3966         int len = list.size();
   3967         for (int i=0; i<len; i++) {
   3968             ToastRecord r = list.get(i);
   3969             if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
   3970                 return i;
   3971             }
   3972         }
   3973         return -1;
   3974     }
   3975 
   3976     @GuardedBy("mToastQueue")
   3977     void keepProcessAliveIfNeededLocked(int pid)
   3978     {
   3979         int toastCount = 0; // toasts from this pid
   3980         ArrayList<ToastRecord> list = mToastQueue;
   3981         int N = list.size();
   3982         for (int i=0; i<N; i++) {
   3983             ToastRecord r = list.get(i);
   3984             if (r.pid == pid) {
   3985                 toastCount++;
   3986             }
   3987         }
   3988         try {
   3989             mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
   3990         } catch (RemoteException e) {
   3991             // Shouldn't happen.
   3992         }
   3993     }
   3994 
   3995     private void handleRankingReconsideration(Message message) {
   3996         if (!(message.obj instanceof RankingReconsideration)) return;
   3997         RankingReconsideration recon = (RankingReconsideration) message.obj;
   3998         recon.run();
   3999         boolean changed;
   4000         synchronized (mNotificationLock) {
   4001             final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
   4002             if (record == null) {
   4003                 return;
   4004             }
   4005             int indexBefore = findNotificationRecordIndexLocked(record);
   4006             boolean interceptBefore = record.isIntercepted();
   4007             int visibilityBefore = record.getPackageVisibilityOverride();
   4008             recon.applyChangesLocked(record);
   4009             applyZenModeLocked(record);
   4010             mRankingHelper.sort(mNotificationList);
   4011             int indexAfter = findNotificationRecordIndexLocked(record);
   4012             boolean interceptAfter = record.isIntercepted();
   4013             int visibilityAfter = record.getPackageVisibilityOverride();
   4014             changed = indexBefore != indexAfter || interceptBefore != interceptAfter
   4015                     || visibilityBefore != visibilityAfter;
   4016             if (interceptBefore && !interceptAfter) {
   4017                 buzzBeepBlinkLocked(record);
   4018             }
   4019         }
   4020         if (changed) {
   4021             scheduleSendRankingUpdate();
   4022         }
   4023     }
   4024 
   4025     private void handleRankingSort(Message msg) {
   4026         if (!(msg.obj instanceof Boolean)) return;
   4027         if (mRankingHelper == null) return;
   4028         boolean forceUpdate = ((Boolean) msg.obj == null) ? false : (boolean) msg.obj;
   4029         synchronized (mNotificationLock) {
   4030             final int N = mNotificationList.size();
   4031             // Any field that can change via one of the extractors or by the assistant
   4032             // needs to be added here.
   4033             ArrayList<String> orderBefore = new ArrayList<String>(N);
   4034             ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
   4035             int[] visibilities = new int[N];
   4036             boolean[] showBadges = new boolean[N];
   4037             for (int i = 0; i < N; i++) {
   4038                 final NotificationRecord r = mNotificationList.get(i);
   4039                 orderBefore.add(r.getKey());
   4040                 groupOverrideBefore.add(r.sbn.getGroupKey());
   4041                 visibilities[i] = r.getPackageVisibilityOverride();
   4042                 showBadges[i] = r.canShowBadge();
   4043                 mRankingHelper.extractSignals(r);
   4044             }
   4045             mRankingHelper.sort(mNotificationList);
   4046             for (int i = 0; i < N; i++) {
   4047                 final NotificationRecord r = mNotificationList.get(i);
   4048                 if (forceUpdate
   4049                         || !orderBefore.get(i).equals(r.getKey())
   4050                         || visibilities[i] != r.getPackageVisibilityOverride()
   4051                         || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())
   4052                         || showBadges[i] != r.canShowBadge()) {
   4053                     scheduleSendRankingUpdate();
   4054                     return;
   4055                 }
   4056             }
   4057         }
   4058     }
   4059 
   4060     @GuardedBy("mNotificationLock")
   4061     private void recordCallerLocked(NotificationRecord record) {
   4062         if (mZenModeHelper.isCall(record)) {
   4063             mZenModeHelper.recordCaller(record);
   4064         }
   4065     }
   4066 
   4067     // let zen mode evaluate this record
   4068     @GuardedBy("mNotificationLock")
   4069     private void applyZenModeLocked(NotificationRecord record) {
   4070         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
   4071         if (record.isIntercepted()) {
   4072             int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
   4073                     ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
   4074                     | (mZenModeHelper.shouldSuppressWhenScreenOn()
   4075                     ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
   4076             record.setSuppressedVisualEffects(suppressed);
   4077         } else {
   4078             record.setSuppressedVisualEffects(0);
   4079         }
   4080     }
   4081 
   4082     @GuardedBy("mNotificationLock")
   4083     private int findNotificationRecordIndexLocked(NotificationRecord target) {
   4084         return mRankingHelper.indexOf(mNotificationList, target);
   4085     }
   4086 
   4087     private void scheduleSendRankingUpdate() {
   4088         if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
   4089             Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
   4090             mHandler.sendMessage(m);
   4091         }
   4092     }
   4093 
   4094     private void handleSendRankingUpdate() {
   4095         synchronized (mNotificationLock) {
   4096             mListeners.notifyRankingUpdateLocked();
   4097         }
   4098     }
   4099 
   4100     private void scheduleListenerHintsChanged(int state) {
   4101         mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
   4102         mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
   4103     }
   4104 
   4105     private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
   4106         mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
   4107         mHandler.obtainMessage(
   4108                 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
   4109                 listenerInterruptionFilter,
   4110                 0).sendToTarget();
   4111     }
   4112 
   4113     private void handleListenerHintsChanged(int hints) {
   4114         synchronized (mNotificationLock) {
   4115             mListeners.notifyListenerHintsChangedLocked(hints);
   4116         }
   4117     }
   4118 
   4119     private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
   4120         synchronized (mNotificationLock) {
   4121             mListeners.notifyInterruptionFilterChanged(interruptionFilter);
   4122         }
   4123     }
   4124 
   4125     private final class WorkerHandler extends Handler
   4126     {
   4127         public WorkerHandler(Looper looper) {
   4128             super(looper);
   4129         }
   4130 
   4131         @Override
   4132         public void handleMessage(Message msg)
   4133         {
   4134             switch (msg.what)
   4135             {
   4136                 case MESSAGE_TIMEOUT:
   4137                     handleTimeout((ToastRecord)msg.obj);
   4138                     break;
   4139                 case MESSAGE_SAVE_POLICY_FILE:
   4140                     handleSavePolicyFile();
   4141                     break;
   4142                 case MESSAGE_SEND_RANKING_UPDATE:
   4143                     handleSendRankingUpdate();
   4144                     break;
   4145                 case MESSAGE_LISTENER_HINTS_CHANGED:
   4146                     handleListenerHintsChanged(msg.arg1);
   4147                     break;
   4148                 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
   4149                     handleListenerInterruptionFilterChanged(msg.arg1);
   4150                     break;
   4151             }
   4152         }
   4153 
   4154     }
   4155 
   4156     private final class RankingHandlerWorker extends Handler implements RankingHandler
   4157     {
   4158         public RankingHandlerWorker(Looper looper) {
   4159             super(looper);
   4160         }
   4161 
   4162         @Override
   4163         public void handleMessage(Message msg) {
   4164             switch (msg.what) {
   4165                 case MESSAGE_RECONSIDER_RANKING:
   4166                     handleRankingReconsideration(msg);
   4167                     break;
   4168                 case MESSAGE_RANKING_SORT:
   4169                     handleRankingSort(msg);
   4170                     break;
   4171             }
   4172         }
   4173 
   4174         public void requestSort(boolean forceUpdate) {
   4175             removeMessages(MESSAGE_RANKING_SORT);
   4176             Message msg = Message.obtain();
   4177             msg.what = MESSAGE_RANKING_SORT;
   4178             msg.obj = forceUpdate;
   4179             sendMessage(msg);
   4180         }
   4181 
   4182         public void requestReconsideration(RankingReconsideration recon) {
   4183             Message m = Message.obtain(this,
   4184                     NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
   4185             long delay = recon.getDelay(TimeUnit.MILLISECONDS);
   4186             sendMessageDelayed(m, delay);
   4187         }
   4188     }
   4189 
   4190     // Notifications
   4191     // ============================================================================
   4192     static int clamp(int x, int low, int high) {
   4193         return (x < low) ? low : ((x > high) ? high : x);
   4194     }
   4195 
   4196     void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
   4197         AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
   4198         if (!manager.isEnabled()) {
   4199             return;
   4200         }
   4201 
   4202         AccessibilityEvent event =
   4203             AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
   4204         event.setPackageName(packageName);
   4205         event.setClassName(Notification.class.getName());
   4206         event.setParcelableData(notification);
   4207         CharSequence tickerText = notification.tickerText;
   4208         if (!TextUtils.isEmpty(tickerText)) {
   4209             event.getText().add(tickerText);
   4210         }
   4211 
   4212         manager.sendAccessibilityEvent(event);
   4213     }
   4214 
   4215     /**
   4216      * Removes all NotificationsRecords with the same key as the given notification record
   4217      * from both lists. Do not call this method while iterating over either list.
   4218      */
   4219     @GuardedBy("mNotificationLock")
   4220     private boolean removeFromNotificationListsLocked(NotificationRecord r) {
   4221         // Remove from both lists, either list could have a separate Record for what is
   4222         // effectively the same notification.
   4223         boolean wasPosted = false;
   4224         NotificationRecord recordInList = null;
   4225         if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
   4226                 != null) {
   4227             mNotificationList.remove(recordInList);
   4228             mNotificationsByKey.remove(recordInList.sbn.getKey());
   4229             wasPosted = true;
   4230         }
   4231         while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
   4232                 != null) {
   4233             mEnqueuedNotifications.remove(recordInList);
   4234         }
   4235         return wasPosted;
   4236     }
   4237 
   4238     @GuardedBy("mNotificationLock")
   4239     private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
   4240             boolean wasPosted) {
   4241         final String canceledKey = r.getKey();
   4242 
   4243         // Record caller.
   4244         recordCallerLocked(r);
   4245 
   4246         // tell the app
   4247         if (sendDelete) {
   4248             if (r.getNotification().deleteIntent != null) {
   4249                 try {
   4250                     r.getNotification().deleteIntent.send();
   4251                 } catch (PendingIntent.CanceledException ex) {
   4252                     // do nothing - there's no relevant way to recover, and
   4253                     //     no reason to let this propagate
   4254                     Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
   4255                 }
   4256             }
   4257         }
   4258 
   4259         // Only cancel these if this notification actually got to be posted.
   4260         if (wasPosted) {
   4261             // status bar
   4262             if (r.getNotification().getSmallIcon() != null) {
   4263                 if (reason != REASON_SNOOZED) {
   4264                     r.isCanceled = true;
   4265                 }
   4266                 mListeners.notifyRemovedLocked(r.sbn, reason);
   4267                 mHandler.post(new Runnable() {
   4268                     @Override
   4269                     public void run() {
   4270                         mGroupHelper.onNotificationRemoved(r.sbn);
   4271                     }
   4272                 });
   4273             }
   4274 
   4275             // sound
   4276             if (canceledKey.equals(mSoundNotificationKey)) {
   4277                 mSoundNotificationKey = null;
   4278                 final long identity = Binder.clearCallingIdentity();
   4279                 try {
   4280                     final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
   4281                     if (player != null) {
   4282                         player.stopAsync();
   4283                     }
   4284                 } catch (RemoteException e) {
   4285                 } finally {
   4286                     Binder.restoreCallingIdentity(identity);
   4287                 }
   4288             }
   4289 
   4290             // vibrate
   4291             if (canceledKey.equals(mVibrateNotificationKey)) {
   4292                 mVibrateNotificationKey = null;
   4293                 long identity = Binder.clearCallingIdentity();
   4294                 try {
   4295                     mVibrator.cancel();
   4296                 }
   4297                 finally {
   4298                     Binder.restoreCallingIdentity(identity);
   4299                 }
   4300             }
   4301 
   4302             // light
   4303             mLights.remove(canceledKey);
   4304         }
   4305 
   4306         // Record usage stats
   4307         // TODO: add unbundling stats?
   4308         switch (reason) {
   4309             case REASON_CANCEL:
   4310             case REASON_CANCEL_ALL:
   4311             case REASON_LISTENER_CANCEL:
   4312             case REASON_LISTENER_CANCEL_ALL:
   4313                 mUsageStats.registerDismissedByUser(r);
   4314                 break;
   4315             case REASON_APP_CANCEL:
   4316             case REASON_APP_CANCEL_ALL:
   4317                 mUsageStats.registerRemovedByApp(r);
   4318                 break;
   4319         }
   4320 
   4321         String groupKey = r.getGroupKey();
   4322         NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
   4323         if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
   4324             mSummaryByGroupKey.remove(groupKey);
   4325         }
   4326         final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
   4327         if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
   4328             summaries.remove(r.sbn.getPackageName());
   4329         }
   4330 
   4331         // Save it for users of getHistoricalNotifications()
   4332         mArchive.record(r.sbn);
   4333 
   4334         final long now = System.currentTimeMillis();
   4335         MetricsLogger.action(r.getLogMaker(now)
   4336                 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
   4337                 .setType(MetricsEvent.TYPE_DISMISS)
   4338                 .setSubtype(reason));
   4339         EventLogTags.writeNotificationCanceled(canceledKey, reason,
   4340                 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
   4341     }
   4342 
   4343     /**
   4344      * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
   4345      * and none of the {@code mustNotHaveFlags}.
   4346      */
   4347     void cancelNotification(final int callingUid, final int callingPid,
   4348             final String pkg, final String tag, final int id,
   4349             final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
   4350             final int userId, final int reason, final ManagedServiceInfo listener) {
   4351         // In enqueueNotificationInternal notifications are added by scheduling the
   4352         // work on the worker handler. Hence, we also schedule the cancel on this
   4353         // handler to avoid a scenario where an add notification call followed by a
   4354         // remove notification call ends up in not removing the notification.
   4355         mHandler.post(new Runnable() {
   4356             @Override
   4357             public void run() {
   4358                 String listenerName = listener == null ? null : listener.component.toShortString();
   4359                 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
   4360                         userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
   4361 
   4362                 synchronized (mNotificationLock) {
   4363                     // Look for the notification, searching both the posted and enqueued lists.
   4364                     NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
   4365                     if (r != null) {
   4366                         // The notification was found, check if it should be removed.
   4367 
   4368                         // Ideally we'd do this in the caller of this method. However, that would
   4369                         // require the caller to also find the notification.
   4370                         if (reason == REASON_CLICK) {
   4371                             mUsageStats.registerClickedByUser(r);
   4372                         }
   4373 
   4374                         if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
   4375                             return;
   4376                         }
   4377                         if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
   4378                             return;
   4379                         }
   4380 
   4381                         // Cancel the notification.
   4382                         boolean wasPosted = removeFromNotificationListsLocked(r);
   4383                         cancelNotificationLocked(r, sendDelete, reason, wasPosted);
   4384                         cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
   4385                                 sendDelete);
   4386                         updateLightsLocked();
   4387                     } else {
   4388                         // No notification was found, assume that it is snoozed and cancel it.
   4389                         if (reason != REASON_SNOOZED) {
   4390                             final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
   4391                             if (wasSnoozed) {
   4392                                 savePolicyFile();
   4393                             }
   4394                         }
   4395                     }
   4396                 }
   4397             }
   4398         });
   4399     }
   4400 
   4401     /**
   4402      * Determine whether the userId applies to the notification in question, either because
   4403      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
   4404      */
   4405     private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
   4406         return
   4407                 // looking for USER_ALL notifications? match everything
   4408                    userId == UserHandle.USER_ALL
   4409                 // a notification sent to USER_ALL matches any query
   4410                 || r.getUserId() == UserHandle.USER_ALL
   4411                 // an exact user match
   4412                 || r.getUserId() == userId;
   4413     }
   4414 
   4415     /**
   4416      * Determine whether the userId applies to the notification in question, either because
   4417      * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
   4418      * because it matches one of the users profiles.
   4419      */
   4420     private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
   4421         return notificationMatchesUserId(r, userId)
   4422                 || mUserProfiles.isCurrentProfile(r.getUserId());
   4423     }
   4424 
   4425     /**
   4426      * Cancels all notifications from a given package that have all of the
   4427      * {@code mustHaveFlags}.
   4428      */
   4429     void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
   4430             int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
   4431             ManagedServiceInfo listener) {
   4432         mHandler.post(new Runnable() {
   4433             @Override
   4434             public void run() {
   4435                 String listenerName = listener == null ? null : listener.component.toShortString();
   4436                 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
   4437                         pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
   4438                         listenerName);
   4439 
   4440                 // Why does this parameter exist? Do we actually want to execute the above if doit
   4441                 // is false?
   4442                 if (!doit) {
   4443                     return;
   4444                 }
   4445 
   4446                 synchronized (mNotificationLock) {
   4447                     FlagChecker flagChecker = (int flags) -> {
   4448                         if ((flags & mustHaveFlags) != mustHaveFlags) {
   4449                             return false;
   4450                         }
   4451                         if ((flags & mustNotHaveFlags) != 0) {
   4452                             return false;
   4453                         }
   4454                         return true;
   4455                     };
   4456 
   4457                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
   4458                             pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
   4459                             false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
   4460                             listenerName, true /* wasPosted */);
   4461                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
   4462                             callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
   4463                             flagChecker, false /*includeCurrentProfiles*/, userId,
   4464                             false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
   4465                     mSnoozeHelper.cancel(userId, pkg);
   4466                 }
   4467             }
   4468         });
   4469     }
   4470 
   4471     private interface FlagChecker {
   4472         // Returns false if these flags do not pass the defined flag test.
   4473         public boolean apply(int flags);
   4474     }
   4475 
   4476     @GuardedBy("mNotificationLock")
   4477     private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
   4478             int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
   4479             String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
   4480             boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
   4481         ArrayList<NotificationRecord> canceledNotifications = null;
   4482         for (int i = notificationList.size() - 1; i >= 0; --i) {
   4483             NotificationRecord r = notificationList.get(i);
   4484             if (includeCurrentProfiles) {
   4485                 if (!notificationMatchesCurrentProfiles(r, userId)) {
   4486                     continue;
   4487                 }
   4488             } else if (!notificationMatchesUserId(r, userId)) {
   4489                 continue;
   4490             }
   4491             // Don't remove notifications to all, if there's no package name specified
   4492             if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
   4493                 continue;
   4494             }
   4495             if (!flagChecker.apply(r.getFlags())) {
   4496                 continue;
   4497             }
   4498             if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
   4499                 continue;
   4500             }
   4501             if (channelId != null && !channelId.equals(r.getChannel().getId())) {
   4502                 continue;
   4503             }
   4504 
   4505             if (canceledNotifications == null) {
   4506                 canceledNotifications = new ArrayList<>();
   4507             }
   4508             notificationList.remove(i);
   4509             canceledNotifications.add(r);
   4510             cancelNotificationLocked(r, sendDelete, reason, wasPosted);
   4511         }
   4512         if (canceledNotifications != null) {
   4513             final int M = canceledNotifications.size();
   4514             for (int i = 0; i < M; i++) {
   4515                 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
   4516                         listenerName, false /* sendDelete */);
   4517             }
   4518             updateLightsLocked();
   4519         }
   4520     }
   4521 
   4522     void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
   4523             ManagedServiceInfo listener) {
   4524         String listenerName = listener == null ? null : listener.component.toShortString();
   4525         if (duration <= 0 && snoozeCriterionId == null || key == null) {
   4526             return;
   4527         }
   4528 
   4529         if (DBG) {
   4530             Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
   4531                     snoozeCriterionId, listenerName));
   4532         }
   4533         // Needs to post so that it can cancel notifications not yet enqueued.
   4534         mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
   4535     }
   4536 
   4537     void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
   4538         String listenerName = listener == null ? null : listener.component.toShortString();
   4539         if (DBG) {
   4540             Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
   4541         }
   4542         mSnoozeHelper.repost(key);
   4543         savePolicyFile();
   4544     }
   4545 
   4546     @GuardedBy("mNotificationLock")
   4547     void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
   4548             ManagedServiceInfo listener, boolean includeCurrentProfiles) {
   4549         mHandler.post(new Runnable() {
   4550             @Override
   4551             public void run() {
   4552                 synchronized (mNotificationLock) {
   4553                     String listenerName =
   4554                             listener == null ? null : listener.component.toShortString();
   4555                     EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
   4556                             null, userId, 0, 0, reason, listenerName);
   4557 
   4558                     FlagChecker flagChecker = (int flags) -> {
   4559                         if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
   4560                                 != 0) {
   4561                             return false;
   4562                         }
   4563                         return true;
   4564                     };
   4565 
   4566                     cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
   4567                             null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
   4568                             includeCurrentProfiles, userId, true /*sendDelete*/, reason,
   4569                             listenerName, true);
   4570                     cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
   4571                             callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
   4572                             flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
   4573                             reason, listenerName, false);
   4574                     mSnoozeHelper.cancel(userId, includeCurrentProfiles);
   4575                 }
   4576             }
   4577         });
   4578     }
   4579 
   4580     // Warning: The caller is responsible for invoking updateLightsLocked().
   4581     @GuardedBy("mNotificationLock")
   4582     private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
   4583             String listenerName, boolean sendDelete) {
   4584         Notification n = r.getNotification();
   4585         if (!n.isGroupSummary()) {
   4586             return;
   4587         }
   4588 
   4589         String pkg = r.sbn.getPackageName();
   4590 
   4591         if (pkg == null) {
   4592             if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
   4593             return;
   4594         }
   4595 
   4596         cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
   4597                 sendDelete, true);
   4598         cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
   4599                 listenerName, sendDelete, false);
   4600     }
   4601 
   4602     @GuardedBy("mNotificationLock")
   4603     private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
   4604             NotificationRecord parentNotification, int callingUid, int callingPid,
   4605             String listenerName, boolean sendDelete, boolean wasPosted) {
   4606         final String pkg = parentNotification.sbn.getPackageName();
   4607         final int userId = parentNotification.getUserId();
   4608         final int reason = REASON_GROUP_SUMMARY_CANCELED;
   4609         for (int i = notificationList.size() - 1; i >= 0; i--) {
   4610             final NotificationRecord childR = notificationList.get(i);
   4611             final StatusBarNotification childSbn = childR.sbn;
   4612             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
   4613                     childR.getGroupKey().equals(parentNotification.getGroupKey())
   4614                     && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
   4615                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
   4616                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
   4617                 notificationList.remove(i);
   4618                 cancelNotificationLocked(childR, sendDelete, reason, wasPosted);
   4619             }
   4620         }
   4621     }
   4622 
   4623     @GuardedBy("mNotificationLock")
   4624     void updateLightsLocked()
   4625     {
   4626         // handle notification lights
   4627         NotificationRecord ledNotification = null;
   4628         while (ledNotification == null && !mLights.isEmpty()) {
   4629             final String owner = mLights.get(mLights.size() - 1);
   4630             ledNotification = mNotificationsByKey.get(owner);
   4631             if (ledNotification == null) {
   4632                 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
   4633                 mLights.remove(owner);
   4634             }
   4635         }
   4636 
   4637         // Don't flash while we are in a call or screen is on
   4638         if (ledNotification == null || mInCall || mScreenOn) {
   4639             mNotificationLight.turnOff();
   4640         } else {
   4641             NotificationRecord.Light light = ledNotification.getLight();
   4642             if (light != null && mNotificationPulseEnabled) {
   4643                 // pulse repeatedly
   4644                 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
   4645                         light.onMs, light.offMs);
   4646             }
   4647         }
   4648     }
   4649 
   4650     @GuardedBy("mNotificationLock")
   4651     @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
   4652             String groupKey, int userId) {
   4653         List<NotificationRecord> records = new ArrayList<>();
   4654         records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
   4655         records.addAll(
   4656                 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
   4657         return records;
   4658     }
   4659 
   4660 
   4661     @GuardedBy("mNotificationLock")
   4662     private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
   4663             ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
   4664         List<NotificationRecord> records = new ArrayList<>();
   4665         final int len = list.size();
   4666         for (int i = 0; i < len; i++) {
   4667             NotificationRecord r = list.get(i);
   4668             if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
   4669                     && r.sbn.getPackageName().equals(pkg)) {
   4670                 records.add(r);
   4671             }
   4672         }
   4673         return records;
   4674     }
   4675 
   4676     // Searches both enqueued and posted notifications by key.
   4677     // TODO: need to combine a bunch of these getters with slightly different behavior.
   4678     // TODO: Should enqueuing just add to mNotificationsByKey instead?
   4679     @GuardedBy("mNotificationLock")
   4680     private NotificationRecord findNotificationByKeyLocked(String key) {
   4681         NotificationRecord r;
   4682         if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
   4683             return r;
   4684         }
   4685         if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
   4686             return r;
   4687         }
   4688         return null;
   4689     }
   4690 
   4691     @GuardedBy("mNotificationLock")
   4692     NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
   4693         NotificationRecord r;
   4694         if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
   4695             return r;
   4696         }
   4697         if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
   4698                 != null) {
   4699             return r;
   4700         }
   4701         return null;
   4702     }
   4703 
   4704     @GuardedBy("mNotificationLock")
   4705     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
   4706             String pkg, String tag, int id, int userId) {
   4707         final int len = list.size();
   4708         for (int i = 0; i < len; i++) {
   4709             NotificationRecord r = list.get(i);
   4710             if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
   4711                     TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
   4712                 return r;
   4713             }
   4714         }
   4715         return null;
   4716     }
   4717 
   4718     @GuardedBy("mNotificationLock")
   4719     private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
   4720             String key) {
   4721         final int N = list.size();
   4722         for (int i = 0; i < N; i++) {
   4723             if (key.equals(list.get(i).getKey())) {
   4724                 return list.get(i);
   4725             }
   4726         }
   4727         return null;
   4728     }
   4729 
   4730     @GuardedBy("mNotificationLock")
   4731     int indexOfNotificationLocked(String key) {
   4732         final int N = mNotificationList.size();
   4733         for (int i = 0; i < N; i++) {
   4734             if (key.equals(mNotificationList.get(i).getKey())) {
   4735                 return i;
   4736             }
   4737         }
   4738         return -1;
   4739     }
   4740 
   4741     private void updateNotificationPulse() {
   4742         synchronized (mNotificationLock) {
   4743             updateLightsLocked();
   4744         }
   4745     }
   4746 
   4747     protected boolean isCallingUidSystem() {
   4748         final int uid = Binder.getCallingUid();
   4749         return uid == Process.SYSTEM_UID;
   4750     }
   4751 
   4752     protected boolean isUidSystemOrPhone(int uid) {
   4753         final int appid = UserHandle.getAppId(uid);
   4754         return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
   4755     }
   4756 
   4757     // TODO: Most calls should probably move to isCallerSystem.
   4758     protected boolean isCallerSystemOrPhone() {
   4759         return isUidSystemOrPhone(Binder.getCallingUid());
   4760     }
   4761 
   4762     private void checkCallerIsSystem() {
   4763         if (isCallerSystemOrPhone()) {
   4764             return;
   4765         }
   4766         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
   4767     }
   4768 
   4769     private void checkCallerIsSystemOrSameApp(String pkg) {
   4770         if (isCallerSystemOrPhone()) {
   4771             return;
   4772         }
   4773         checkCallerIsSameApp(pkg);
   4774     }
   4775 
   4776     private boolean isCallerInstantApp(String pkg) {
   4777         // System is always allowed to act for ephemeral apps.
   4778         if (isCallerSystemOrPhone()) {
   4779             return false;
   4780         }
   4781 
   4782         mAppOps.checkPackage(Binder.getCallingUid(), pkg);
   4783 
   4784         try {
   4785             ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
   4786                     UserHandle.getCallingUserId());
   4787             if (ai == null) {
   4788                 throw new SecurityException("Unknown package " + pkg);
   4789             }
   4790             return ai.isInstantApp();
   4791         } catch (RemoteException re) {
   4792             throw new SecurityException("Unknown package " + pkg, re);
   4793         }
   4794 
   4795     }
   4796 
   4797     private void checkCallerIsSameApp(String pkg) {
   4798         final int uid = Binder.getCallingUid();
   4799         try {
   4800             ApplicationInfo ai = mPackageManager.getApplicationInfo(
   4801                     pkg, 0, UserHandle.getCallingUserId());
   4802             if (ai == null) {
   4803                 throw new SecurityException("Unknown package " + pkg);
   4804             }
   4805             if (!UserHandle.isSameApp(ai.uid, uid)) {
   4806                 throw new SecurityException("Calling uid " + uid + " gave package "
   4807                         + pkg + " which is owned by uid " + ai.uid);
   4808             }
   4809         } catch (RemoteException re) {
   4810             throw new SecurityException("Unknown package " + pkg + "\n" + re);
   4811         }
   4812     }
   4813 
   4814     private static String callStateToString(int state) {
   4815         switch (state) {
   4816             case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
   4817             case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
   4818             case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
   4819             default: return "CALL_STATE_UNKNOWN_" + state;
   4820         }
   4821     }
   4822 
   4823     private void listenForCallState() {
   4824         TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
   4825             @Override
   4826             public void onCallStateChanged(int state, String incomingNumber) {
   4827                 if (mCallState == state) return;
   4828                 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
   4829                 mCallState = state;
   4830             }
   4831         }, PhoneStateListener.LISTEN_CALL_STATE);
   4832     }
   4833 
   4834     /**
   4835      * Generates a NotificationRankingUpdate from 'sbns', considering only
   4836      * notifications visible to the given listener.
   4837      */
   4838     @GuardedBy("mNotificationLock")
   4839     private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
   4840         final int N = mNotificationList.size();
   4841         ArrayList<String> keys = new ArrayList<String>(N);
   4842         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
   4843         ArrayList<Integer> importance = new ArrayList<>(N);
   4844         Bundle overrideGroupKeys = new Bundle();
   4845         Bundle visibilityOverrides = new Bundle();
   4846         Bundle suppressedVisualEffects = new Bundle();
   4847         Bundle explanation = new Bundle();
   4848         Bundle channels = new Bundle();
   4849         Bundle overridePeople = new Bundle();
   4850         Bundle snoozeCriteria = new Bundle();
   4851         Bundle showBadge = new Bundle();
   4852         for (int i = 0; i < N; i++) {
   4853             NotificationRecord record = mNotificationList.get(i);
   4854             if (!isVisibleToListener(record.sbn, info)) {
   4855                 continue;
   4856             }
   4857             final String key = record.sbn.getKey();
   4858             keys.add(key);
   4859             importance.add(record.getImportance());
   4860             if (record.getImportanceExplanation() != null) {
   4861                 explanation.putCharSequence(key, record.getImportanceExplanation());
   4862             }
   4863             if (record.isIntercepted()) {
   4864                 interceptedKeys.add(key);
   4865 
   4866             }
   4867             suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
   4868             if (record.getPackageVisibilityOverride()
   4869                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
   4870                 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
   4871             }
   4872             overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
   4873             channels.putParcelable(key, record.getChannel());
   4874             overridePeople.putStringArrayList(key, record.getPeopleOverride());
   4875             snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
   4876             showBadge.putBoolean(key, record.canShowBadge());
   4877         }
   4878         final int M = keys.size();
   4879         String[] keysAr = keys.toArray(new String[M]);
   4880         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
   4881         int[] importanceAr = new int[M];
   4882         for (int i = 0; i < M; i++) {
   4883             importanceAr[i] = importance.get(i);
   4884         }
   4885         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
   4886                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
   4887                 channels, overridePeople, snoozeCriteria, showBadge);
   4888     }
   4889 
   4890     boolean hasCompanionDevice(ManagedServiceInfo info) {
   4891         if (mCompanionManager == null) {
   4892             mCompanionManager = getCompanionManager();
   4893         }
   4894         // Companion mgr doesn't exist on all device types
   4895         if (mCompanionManager == null) {
   4896             return false;
   4897         }
   4898         long identity = Binder.clearCallingIdentity();
   4899         try {
   4900             List<String> associations = mCompanionManager.getAssociations(
   4901                     info.component.getPackageName(), info.userid);
   4902             if (!ArrayUtils.isEmpty(associations)) {
   4903                 return true;
   4904             }
   4905         } catch (SecurityException se) {
   4906             // Not a privileged listener
   4907         } catch (RemoteException re) {
   4908             Slog.e(TAG, "Cannot reach companion device service", re);
   4909         } catch (Exception e) {
   4910             Slog.e(TAG, "Cannot verify listener " + info, e);
   4911         } finally {
   4912             Binder.restoreCallingIdentity(identity);
   4913         }
   4914         return false;
   4915     }
   4916 
   4917     protected ICompanionDeviceManager getCompanionManager() {
   4918         return ICompanionDeviceManager.Stub.asInterface(
   4919                 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
   4920     }
   4921 
   4922     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
   4923         if (!listener.enabledAndUserMatches(sbn.getUserId())) {
   4924             return false;
   4925         }
   4926         // TODO: remove this for older listeners.
   4927         return true;
   4928     }
   4929 
   4930     private boolean isPackageSuspendedForUser(String pkg, int uid) {
   4931         int userId = UserHandle.getUserId(uid);
   4932         try {
   4933             return mPackageManager.isPackageSuspendedForUser(pkg, userId);
   4934         } catch (RemoteException re) {
   4935             throw new SecurityException("Could not talk to package manager service");
   4936         } catch (IllegalArgumentException ex) {
   4937             // Package not found.
   4938             return false;
   4939         }
   4940     }
   4941 
   4942     private class TrimCache {
   4943         StatusBarNotification heavy;
   4944         StatusBarNotification sbnClone;
   4945         StatusBarNotification sbnCloneLight;
   4946 
   4947         TrimCache(StatusBarNotification sbn) {
   4948             heavy = sbn;
   4949         }
   4950 
   4951         StatusBarNotification ForListener(ManagedServiceInfo info) {
   4952             if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
   4953                 if (sbnCloneLight == null) {
   4954                     sbnCloneLight = heavy.cloneLight();
   4955                 }
   4956                 return sbnCloneLight;
   4957             } else {
   4958                 if (sbnClone == null) {
   4959                     sbnClone = heavy.clone();
   4960                 }
   4961                 return sbnClone;
   4962             }
   4963         }
   4964     }
   4965 
   4966     public class NotificationAssistants extends ManagedServices {
   4967 
   4968         public NotificationAssistants() {
   4969             super(getContext(), mHandler, mNotificationLock, mUserProfiles);
   4970         }
   4971 
   4972         @Override
   4973         protected Config getConfig() {
   4974             Config c = new Config();
   4975             c.caption = "notification assistant service";
   4976             c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
   4977             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
   4978             c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
   4979             c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
   4980             c.clientLabel = R.string.notification_ranker_binding_label;
   4981             return c;
   4982         }
   4983 
   4984         @Override
   4985         protected IInterface asInterface(IBinder binder) {
   4986             return INotificationListener.Stub.asInterface(binder);
   4987         }
   4988 
   4989         @Override
   4990         protected boolean checkType(IInterface service) {
   4991             return service instanceof INotificationListener;
   4992         }
   4993 
   4994         @Override
   4995         protected void onServiceAdded(ManagedServiceInfo info) {
   4996             mListeners.registerGuestService(info);
   4997         }
   4998 
   4999         @Override
   5000         @GuardedBy("mNotificationLock")
   5001         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
   5002             mListeners.unregisterService(removed.service, removed.userid);
   5003         }
   5004 
   5005         public void onNotificationEnqueued(final NotificationRecord r) {
   5006             final StatusBarNotification sbn = r.sbn;
   5007             TrimCache trimCache = new TrimCache(sbn);
   5008 
   5009             // There should be only one, but it's a list, so while we enforce
   5010             // singularity elsewhere, we keep it general here, to avoid surprises.
   5011             for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
   5012                 boolean sbnVisible = isVisibleToListener(sbn, info);
   5013                 if (!sbnVisible) {
   5014                     continue;
   5015                 }
   5016 
   5017                 final int importance = r.getImportance();
   5018                 final boolean fromUser = r.isImportanceFromUser();
   5019                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
   5020                 mHandler.post(new Runnable() {
   5021                     @Override
   5022                     public void run() {
   5023                         notifyEnqueued(info, sbnToPost);
   5024                     }
   5025                 });
   5026             }
   5027         }
   5028 
   5029         private void notifyEnqueued(final ManagedServiceInfo info,
   5030                 final StatusBarNotification sbn) {
   5031             final INotificationListener assistant = (INotificationListener) info.service;
   5032             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
   5033             try {
   5034                 assistant.onNotificationEnqueued(sbnHolder);
   5035             } catch (RemoteException ex) {
   5036                 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
   5037             }
   5038         }
   5039 
   5040         /**
   5041          * asynchronously notify the assistant that a notification has been snoozed until a
   5042          * context
   5043          */
   5044         @GuardedBy("mNotificationLock")
   5045         public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
   5046                 final String snoozeCriterionId) {
   5047             TrimCache trimCache = new TrimCache(sbn);
   5048             for (final ManagedServiceInfo info : getServices()) {
   5049                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
   5050                 mHandler.post(new Runnable() {
   5051                     @Override
   5052                     public void run() {
   5053                         final INotificationListener assistant =
   5054                                 (INotificationListener) info.service;
   5055                         StatusBarNotificationHolder sbnHolder
   5056                                 = new StatusBarNotificationHolder(sbnToPost);
   5057                         try {
   5058                             assistant.onNotificationSnoozedUntilContext(
   5059                                     sbnHolder, snoozeCriterionId);
   5060                         } catch (RemoteException ex) {
   5061                             Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
   5062                         }
   5063                     }
   5064                 });
   5065             }
   5066         }
   5067 
   5068         public boolean isEnabled() {
   5069             return !getServices().isEmpty();
   5070         }
   5071     }
   5072 
   5073     public class NotificationListeners extends ManagedServices {
   5074 
   5075         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
   5076 
   5077         public NotificationListeners() {
   5078             super(getContext(), mHandler, mNotificationLock, mUserProfiles);
   5079         }
   5080 
   5081         @Override
   5082         protected Config getConfig() {
   5083             Config c = new Config();
   5084             c.caption = "notification listener";
   5085             c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
   5086             c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
   5087             c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
   5088             c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
   5089             c.clientLabel = R.string.notification_listener_binding_label;
   5090             return c;
   5091         }
   5092 
   5093         @Override
   5094         protected IInterface asInterface(IBinder binder) {
   5095             return INotificationListener.Stub.asInterface(binder);
   5096         }
   5097 
   5098         @Override
   5099         protected boolean checkType(IInterface service) {
   5100             return service instanceof INotificationListener;
   5101         }
   5102 
   5103         @Override
   5104         public void onServiceAdded(ManagedServiceInfo info) {
   5105             final INotificationListener listener = (INotificationListener) info.service;
   5106             final NotificationRankingUpdate update;
   5107             synchronized (mNotificationLock) {
   5108                 update = makeRankingUpdateLocked(info);
   5109             }
   5110             try {
   5111                 listener.onListenerConnected(update);
   5112             } catch (RemoteException e) {
   5113                 // we tried
   5114             }
   5115         }
   5116 
   5117         @Override
   5118         @GuardedBy("mNotificationLock")
   5119         protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
   5120             if (removeDisabledHints(removed)) {
   5121                 updateListenerHintsLocked();
   5122                 updateEffectsSuppressorLocked();
   5123             }
   5124             mLightTrimListeners.remove(removed);
   5125         }
   5126 
   5127         @GuardedBy("mNotificationLock")
   5128         public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
   5129             if (trim == TRIM_LIGHT) {
   5130                 mLightTrimListeners.add(info);
   5131             } else {
   5132                 mLightTrimListeners.remove(info);
   5133             }
   5134         }
   5135 
   5136         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
   5137             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
   5138         }
   5139 
   5140         /**
   5141          * asynchronously notify all listeners about a new notification
   5142          *
   5143          * <p>
   5144          * Also takes care of removing a notification that has been visible to a listener before,
   5145          * but isn't anymore.
   5146          */
   5147         @GuardedBy("mNotificationLock")
   5148         public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
   5149             // Lazily initialized snapshots of the notification.
   5150             TrimCache trimCache = new TrimCache(sbn);
   5151 
   5152             for (final ManagedServiceInfo info : getServices()) {
   5153                 boolean sbnVisible = isVisibleToListener(sbn, info);
   5154                 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
   5155                 // This notification hasn't been and still isn't visible -> ignore.
   5156                 if (!oldSbnVisible && !sbnVisible) {
   5157                     continue;
   5158                 }
   5159                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
   5160 
   5161                 // This notification became invisible -> remove the old one.
   5162                 if (oldSbnVisible && !sbnVisible) {
   5163                     final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
   5164                     mHandler.post(new Runnable() {
   5165                         @Override
   5166                         public void run() {
   5167                             notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
   5168                         }
   5169                     });
   5170                     continue;
   5171                 }
   5172 
   5173                 final StatusBarNotification sbnToPost =  trimCache.ForListener(info);
   5174                 mHandler.post(new Runnable() {
   5175                     @Override
   5176                     public void run() {
   5177                         notifyPosted(info, sbnToPost, update);
   5178                     }
   5179                 });
   5180             }
   5181         }
   5182 
   5183         /**
   5184          * asynchronously notify all listeners about a removed notification
   5185          */
   5186         @GuardedBy("mNotificationLock")
   5187         public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
   5188             // make a copy in case changes are made to the underlying Notification object
   5189             // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
   5190             // notification
   5191             final StatusBarNotification sbnLight = sbn.cloneLight();
   5192             for (final ManagedServiceInfo info : getServices()) {
   5193                 if (!isVisibleToListener(sbn, info)) {
   5194                     continue;
   5195                 }
   5196                 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
   5197                 mHandler.post(new Runnable() {
   5198                     @Override
   5199                     public void run() {
   5200                         notifyRemoved(info, sbnLight, update, reason);
   5201                     }
   5202                 });
   5203             }
   5204         }
   5205 
   5206         /**
   5207          * asynchronously notify all listeners about a reordering of notifications
   5208          */
   5209         @GuardedBy("mNotificationLock")
   5210         public void notifyRankingUpdateLocked() {
   5211             for (final ManagedServiceInfo serviceInfo : getServices()) {
   5212                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
   5213                     continue;
   5214                 }
   5215                 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
   5216                 mHandler.post(new Runnable() {
   5217                     @Override
   5218                     public void run() {
   5219                         notifyRankingUpdate(serviceInfo, update);
   5220                     }
   5221                 });
   5222             }
   5223         }
   5224 
   5225         @GuardedBy("mNotificationLock")
   5226         public void notifyListenerHintsChangedLocked(final int hints) {
   5227             for (final ManagedServiceInfo serviceInfo : getServices()) {
   5228                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
   5229                     continue;
   5230                 }
   5231                 mHandler.post(new Runnable() {
   5232                     @Override
   5233                     public void run() {
   5234                         notifyListenerHintsChanged(serviceInfo, hints);
   5235                     }
   5236                 });
   5237             }
   5238         }
   5239 
   5240         public void notifyInterruptionFilterChanged(final int interruptionFilter) {
   5241             for (final ManagedServiceInfo serviceInfo : getServices()) {
   5242                 if (!serviceInfo.isEnabledForCurrentProfiles()) {
   5243                     continue;
   5244                 }
   5245                 mHandler.post(new Runnable() {
   5246                     @Override
   5247                     public void run() {
   5248                         notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
   5249                     }
   5250                 });
   5251             }
   5252         }
   5253 
   5254         protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
   5255                 final NotificationChannel channel, final int modificationType) {
   5256             if (channel == null) {
   5257                 return;
   5258             }
   5259             for (final ManagedServiceInfo serviceInfo : getServices()) {
   5260                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
   5261                     continue;
   5262                 }
   5263 
   5264                 mHandler.post(new Runnable() {
   5265                     @Override
   5266                     public void run() {
   5267                         if (hasCompanionDevice(serviceInfo)) {
   5268                             notifyNotificationChannelChanged(
   5269                                     serviceInfo, pkg, user, channel, modificationType);
   5270                         }
   5271                     }
   5272                 });
   5273             }
   5274         }
   5275 
   5276         protected void notifyNotificationChannelGroupChanged(
   5277                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
   5278                 final int modificationType) {
   5279             if (group == null) {
   5280                 return;
   5281             }
   5282             for (final ManagedServiceInfo serviceInfo : getServices()) {
   5283                 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
   5284                     continue;
   5285                 }
   5286 
   5287                 mHandler.post(new Runnable() {
   5288                     @Override
   5289                     public void run() {
   5290                         if (hasCompanionDevice(serviceInfo)) {
   5291                             notifyNotificationChannelGroupChanged(
   5292                                     serviceInfo, pkg, user, group, modificationType);
   5293                         }
   5294                     }
   5295                 });
   5296             }
   5297         }
   5298 
   5299         private void notifyPosted(final ManagedServiceInfo info,
   5300                 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
   5301             final INotificationListener listener = (INotificationListener) info.service;
   5302             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
   5303             try {
   5304                 listener.onNotificationPosted(sbnHolder, rankingUpdate);
   5305             } catch (RemoteException ex) {
   5306                 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
   5307             }
   5308         }
   5309 
   5310         private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
   5311                 NotificationRankingUpdate rankingUpdate, int reason) {
   5312             if (!info.enabledAndUserMatches(sbn.getUserId())) {
   5313                 return;
   5314             }
   5315             final INotificationListener listener = (INotificationListener) info.service;
   5316             StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
   5317             try {
   5318                 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
   5319             } catch (RemoteException ex) {
   5320                 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
   5321             }
   5322         }
   5323 
   5324         private void notifyRankingUpdate(ManagedServiceInfo info,
   5325                                          NotificationRankingUpdate rankingUpdate) {
   5326             final INotificationListener listener = (INotificationListener) info.service;
   5327             try {
   5328                 listener.onNotificationRankingUpdate(rankingUpdate);
   5329             } catch (RemoteException ex) {
   5330                 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
   5331             }
   5332         }
   5333 
   5334         private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
   5335             final INotificationListener listener = (INotificationListener) info.service;
   5336             try {
   5337                 listener.onListenerHintsChanged(hints);
   5338             } catch (RemoteException ex) {
   5339                 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
   5340             }
   5341         }
   5342 
   5343         private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
   5344                 int interruptionFilter) {
   5345             final INotificationListener listener = (INotificationListener) info.service;
   5346             try {
   5347                 listener.onInterruptionFilterChanged(interruptionFilter);
   5348             } catch (RemoteException ex) {
   5349                 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
   5350             }
   5351         }
   5352 
   5353         void notifyNotificationChannelChanged(ManagedServiceInfo info,
   5354                 final String pkg, final UserHandle user, final NotificationChannel channel,
   5355                 final int modificationType) {
   5356             final INotificationListener listener = (INotificationListener) info.service;
   5357             try {
   5358                 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
   5359             } catch (RemoteException ex) {
   5360                 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
   5361             }
   5362         }
   5363 
   5364         private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
   5365                 final String pkg, final UserHandle user, final NotificationChannelGroup group,
   5366                 final int modificationType) {
   5367             final INotificationListener listener = (INotificationListener) info.service;
   5368             try {
   5369                 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
   5370             } catch (RemoteException ex) {
   5371                 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
   5372             }
   5373         }
   5374 
   5375         public boolean isListenerPackage(String packageName) {
   5376             if (packageName == null) {
   5377                 return false;
   5378             }
   5379             // TODO: clean up locking object later
   5380             synchronized (mNotificationLock) {
   5381                 for (final ManagedServiceInfo serviceInfo : getServices()) {
   5382                     if (packageName.equals(serviceInfo.component.getPackageName())) {
   5383                         return true;
   5384                     }
   5385                 }
   5386             }
   5387             return false;
   5388         }
   5389     }
   5390 
   5391     public static final class DumpFilter {
   5392         public boolean filtered = false;
   5393         public String pkgFilter;
   5394         public boolean zen;
   5395         public long since;
   5396         public boolean stats;
   5397         public boolean redact = true;
   5398         public boolean proto = false;
   5399 
   5400         public static DumpFilter parseFromArguments(String[] args) {
   5401             final DumpFilter filter = new DumpFilter();
   5402             for (int ai = 0; ai < args.length; ai++) {
   5403                 final String a = args[ai];
   5404                 if ("--proto".equals(args[0])) {
   5405                     filter.proto = true;
   5406                 }
   5407                 if ("--noredact".equals(a) || "--reveal".equals(a)) {
   5408                     filter.redact = false;
   5409                 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
   5410                     if (ai < args.length-1) {
   5411                         ai++;
   5412                         filter.pkgFilter = args[ai].trim().toLowerCase();
   5413                         if (filter.pkgFilter.isEmpty()) {
   5414                             filter.pkgFilter = null;
   5415                         } else {
   5416                             filter.filtered = true;
   5417                         }
   5418                     }
   5419                 } else if ("--zen".equals(a) || "zen".equals(a)) {
   5420                     filter.filtered = true;
   5421                     filter.zen = true;
   5422                 } else if ("--stats".equals(a)) {
   5423                     filter.stats = true;
   5424                     if (ai < args.length-1) {
   5425                         ai++;
   5426                         filter.since = Long.parseLong(args[ai]);
   5427                     } else {
   5428                         filter.since = 0;
   5429                     }
   5430                 }
   5431             }
   5432             return filter;
   5433         }
   5434 
   5435         public boolean matches(StatusBarNotification sbn) {
   5436             if (!filtered) return true;
   5437             return zen ? true : sbn != null
   5438                     && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
   5439         }
   5440 
   5441         public boolean matches(ComponentName component) {
   5442             if (!filtered) return true;
   5443             return zen ? true : component != null && matches(component.getPackageName());
   5444         }
   5445 
   5446         public boolean matches(String pkg) {
   5447             if (!filtered) return true;
   5448             return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
   5449         }
   5450 
   5451         @Override
   5452         public String toString() {
   5453             return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
   5454         }
   5455     }
   5456 
   5457     /**
   5458      * Wrapper for a StatusBarNotification object that allows transfer across a oneway
   5459      * binder without sending large amounts of data over a oneway transaction.
   5460      */
   5461     private static final class StatusBarNotificationHolder
   5462             extends IStatusBarNotificationHolder.Stub {
   5463         private StatusBarNotification mValue;
   5464 
   5465         public StatusBarNotificationHolder(StatusBarNotification value) {
   5466             mValue = value;
   5467         }
   5468 
   5469         /** Get the held value and clear it. This function should only be called once per holder */
   5470         @Override
   5471         public StatusBarNotification get() {
   5472             StatusBarNotification value = mValue;
   5473             mValue = null;
   5474             return value;
   5475         }
   5476     }
   5477 
   5478     private final class PolicyAccess {
   5479         private static final String SEPARATOR = ":";
   5480         private final String[] PERM = {
   5481             android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
   5482         };
   5483 
   5484         public boolean isPackageGranted(String pkg) {
   5485             return pkg != null && getGrantedPackages().contains(pkg);
   5486         }
   5487 
   5488         public void put(String pkg, boolean granted) {
   5489             if (pkg == null) return;
   5490             final ArraySet<String> pkgs = getGrantedPackages();
   5491             boolean changed;
   5492             if (granted) {
   5493                 changed = pkgs.add(pkg);
   5494             } else {
   5495                 changed = pkgs.remove(pkg);
   5496             }
   5497             if (!changed) return;
   5498             final String setting = TextUtils.join(SEPARATOR, pkgs);
   5499             final int currentUser = ActivityManager.getCurrentUser();
   5500             Settings.Secure.putStringForUser(getContext().getContentResolver(),
   5501                     Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
   5502                     setting,
   5503                     currentUser);
   5504             getContext().sendBroadcastAsUser(new Intent(NotificationManager
   5505                     .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
   5506                 .setPackage(pkg)
   5507                 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
   5508         }
   5509 
   5510         public ArraySet<String> getGrantedPackages() {
   5511             final ArraySet<String> pkgs = new ArraySet<>();
   5512 
   5513             long identity = Binder.clearCallingIdentity();
   5514             try {
   5515                 final String setting = Settings.Secure.getStringForUser(
   5516                         getContext().getContentResolver(),
   5517                         Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
   5518                         ActivityManager.getCurrentUser());
   5519                 if (setting != null) {
   5520                     final String[] tokens = setting.split(SEPARATOR);
   5521                     for (int i = 0; i < tokens.length; i++) {
   5522                         String token = tokens[i];
   5523                         if (token != null) {
   5524                             token = token.trim();
   5525                         }
   5526                         if (TextUtils.isEmpty(token)) {
   5527                             continue;
   5528                         }
   5529                         pkgs.add(token);
   5530                     }
   5531                 }
   5532             } finally {
   5533                 Binder.restoreCallingIdentity(identity);
   5534             }
   5535             return pkgs;
   5536         }
   5537 
   5538         public String[] getRequestingPackages() throws RemoteException {
   5539             final ParceledListSlice list = mPackageManager
   5540                     .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
   5541                             ActivityManager.getCurrentUser());
   5542             final List<PackageInfo> pkgs = list.getList();
   5543             if (pkgs == null || pkgs.isEmpty()) return new String[0];
   5544             final int N = pkgs.size();
   5545             final String[] rt = new String[N];
   5546             for (int i = 0; i < N; i++) {
   5547                 rt[i] = pkgs.get(i).packageName;
   5548             }
   5549             return rt;
   5550         }
   5551     }
   5552 }
   5553