blob: c337c573ffb420a2e7148fefd6a437e61e0bc9f7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Adam Lesinski182f73f2013-12-05 16:48:06 -080017package com.android.server.notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Chris Wren9fa689f2015-11-20 16:44:53 -050019import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL;
20import static android.service.notification.NotificationAssistantService.REASON_APP_CANCEL_ALL;
Jason Monk63506742015-12-16 12:06:51 -050021import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL;
22import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CANCEL_ALL;
23import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_CLICK;
24import static android.service.notification.NotificationAssistantService.REASON_DELEGATE_ERROR;
25import static android.service.notification.NotificationAssistantService.REASON_GROUP_OPTIMIZATION;
26import static android.service.notification.NotificationAssistantService.REASON_GROUP_SUMMARY_CANCELED;
Chris Wren9fa689f2015-11-20 16:44:53 -050027import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL;
28import static android.service.notification.NotificationAssistantService.REASON_LISTENER_CANCEL_ALL;
Jason Monk63506742015-12-16 12:06:51 -050029import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_BANNED;
30import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_CHANGED;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +000031import static android.service.notification.NotificationAssistantService.REASON_PACKAGE_SUSPENDED;
Rubin Xu7eadc1b2016-02-01 16:13:45 +000032import static android.service.notification.NotificationAssistantService.REASON_PROFILE_TURNED_OFF;
Jason Monk63506742015-12-16 12:06:51 -050033import static android.service.notification.NotificationAssistantService.REASON_USER_STOPPED;
34import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
Julia Reynoldsd5607292016-02-05 15:25:58 -050035import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
Julia Reynolds61721582016-01-05 08:35:25 -050036import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
Christoph Studerb82bc782014-08-20 14:29:43 +020037import static android.service.notification.NotificationListenerService.TRIM_FULL;
38import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Rubin Xu7eadc1b2016-02-01 16:13:45 +000039import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
Chris Wren4a4b49d2016-02-09 11:25:08 -050040import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
Jeff Sharkey098d5802012-04-26 17:30:34 -070041import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
42import static org.xmlpull.v1.XmlPullParser.END_TAG;
43import static org.xmlpull.v1.XmlPullParser.START_TAG;
svetoslavganov75986cf2009-05-14 22:28:01 -070044
Chris Wren51017d02015-12-15 15:34:46 -050045import android.Manifest;
Dianne Hackborn41203752012-08-31 14:05:51 -070046import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.app.ActivityManagerNative;
John Spurlock7340fc82014-04-24 18:50:12 -040048import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050049import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040050import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.app.IActivityManager;
52import android.app.INotificationManager;
53import android.app.ITransientNotification;
54import android.app.Notification;
John Spurlockb4782522014-08-22 14:54:46 -040055import android.app.NotificationManager;
John Spurlock1fc476d2015-04-14 16:05:20 -040056import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.app.PendingIntent;
58import android.app.StatusBarManager;
John Spurlock35ef0a62015-05-28 11:24:10 -040059import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070060import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070061import android.app.usage.UsageStatsManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070063import android.content.ComponentName;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070064import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.content.Context;
66import android.content.Intent;
67import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040068import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +000069import android.content.pm.IPackageManager;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050070import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.content.pm.PackageManager;
72import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +020073import android.content.pm.ParceledListSlice;
Chris Wren66189fc2015-06-25 14:04:33 -040074import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070076import android.database.ContentObserver;
John Spurlock7b414672014-07-18 13:02:39 -040077import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -070078import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -050079import android.media.AudioManagerInternal;
Jean-Michel Triviceb79bc2014-09-05 11:09:14 -070080import android.media.AudioSystem;
Jeff Sharkey098d5802012-04-26 17:30:34 -070081import android.media.IRingtonePlayer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.os.Binder;
John Spurlock2b122f42014-08-27 16:29:47 -040084import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -040085import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -040087import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.os.IBinder;
John Spurlock7340fc82014-04-24 18:50:12 -040089import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -040090import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070092import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070093import android.os.RemoteException;
Selim Cinekb5605e52015-02-20 18:21:41 +010094import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070095import android.os.UserHandle;
Chris Wren66189fc2015-06-25 14:04:33 -040096import android.os.UserManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.os.Vibrator;
98import android.provider.Settings;
Chris Wren333a61c2014-05-28 16:40:57 -040099import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400100import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400101import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700102import android.service.notification.IStatusBarNotificationHolder;
Chris Wren51017d02015-12-15 15:34:46 -0500103import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400104import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200105import android.service.notification.NotificationRankingUpdate;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700106import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400107import android.service.notification.ZenModeConfig;
John Spurlock32fe4c62014-10-02 12:16:02 -0400108import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500109import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700110import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400111import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400112import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700113import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800115import android.util.Slog;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400116import android.util.Xml;
svetoslavganov75986cf2009-05-14 22:28:01 -0700117import android.view.accessibility.AccessibilityEvent;
118import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000120
Scott Greenwald9a05b312013-06-28 00:37:54 -0400121import com.android.internal.R;
Chris Wrend1dbc922015-06-19 17:51:16 -0400122import com.android.internal.statusbar.NotificationVisibility;
John Spurlock056c5192014-04-20 21:52:01 -0400123import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400124import com.android.internal.util.Preconditions;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800125import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700126import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800127import com.android.server.SystemService;
128import com.android.server.lights.Light;
129import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400130import com.android.server.notification.ManagedServices.ManagedServiceInfo;
131import com.android.server.notification.ManagedServices.UserProfiles;
John Spurlockb408e8e2014-04-23 21:12:45 -0400132import com.android.server.statusbar.StatusBarManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800133import com.android.server.vr.VrManagerInternal;
134import com.android.server.vr.VrStateListener;
135
John Spurlockb408e8e2014-04-23 21:12:45 -0400136import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000137
Chris Wrene4b38802015-07-07 15:54:19 -0400138import org.json.JSONArray;
139import org.json.JSONException;
140import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700141import org.xmlpull.v1.XmlPullParser;
142import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400143import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700144
John Spurlock35ef0a62015-05-28 11:24:10 -0400145import java.io.ByteArrayInputStream;
146import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400147import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400149import java.io.FileInputStream;
150import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400151import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400152import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400153import java.io.InputStream;
154import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100156import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500157import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158import java.util.ArrayList;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400159import java.util.HashSet;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500160import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400161import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200162import java.util.Map.Entry;
John Spurlockb4782522014-08-22 14:54:46 -0400163import java.util.Objects;
Chris Wren51017d02015-12-15 15:34:46 -0500164import java.util.concurrent.TimeUnit;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400165
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400166/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800167public class NotificationManagerService extends SystemService {
168 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100169 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800170 public static final boolean ENABLE_CHILD_NOTIFICATIONS
171 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172
Adam Lesinski182f73f2013-12-05 16:48:06 -0800173 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Joe Onoratobd73d012010-06-04 11:44:54 -0700174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 // message codes
Adam Lesinski182f73f2013-12-05 16:48:06 -0800176 static final int MESSAGE_TIMEOUT = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400177 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500178 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
179 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
180 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
181
182 // ranking thread messages
183 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
184 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
Adam Lesinski182f73f2013-12-05 16:48:06 -0800186 static final int LONG_DELAY = 3500; // 3.5 seconds
187 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800188
Adam Lesinski182f73f2013-12-05 16:48:06 -0800189 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200190
Adam Lesinski182f73f2013-12-05 16:48:06 -0800191 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192
Adam Lesinski182f73f2013-12-05 16:48:06 -0800193 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500194
Adam Lesinski182f73f2013-12-05 16:48:06 -0800195 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
196 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400197
Christoph Studer12aeda82014-09-23 19:08:56 +0200198 // When #matchesCallFilter is called from the ringer, wait at most
199 // 3s to resolve the contacts. This timeout is required since
200 // ContactsProvider might take a long time to start up.
201 //
202 // Return STARRED_CONTACT when the timeout is hit in order to avoid
203 // missed calls in ZEN mode "Important".
204 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
205 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
206 ValidateNotificationPeople.STARRED_CONTACT;
207
Christoph Studer265c1052014-07-23 17:14:33 +0200208 /** notification_enqueue status value for a newly enqueued notification. */
209 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
210
211 /** notification_enqueue status value for an existing notification. */
212 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
213
214 /** notification_enqueue status value for an ignored notification. */
215 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
216
Adam Lesinski182f73f2013-12-05 16:48:06 -0800217 private IActivityManager mAm;
218 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500219 AudioManagerInternal mAudioManagerInternal;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800220 StatusBarManagerInternal mStatusBar;
221 Vibrator mVibrator;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800222 private VrManagerInternal mVrManagerInternal;
223 private final NotificationVrListener mVrListener = new NotificationVrListener();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 final IBinder mForegroundToken = new Binder();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400227 private final HandlerThread mRankingThread = new HandlerThread("ranker",
228 Process.THREAD_PRIORITY_BACKGROUND);
Chris Wren47633422016-01-22 09:56:59 -0500229 private final HandlerThread mAssistantThread = new HandlerThread("assistant",
230 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231
Adam Lesinski182f73f2013-12-05 16:48:06 -0800232 private Light mNotificationLight;
233 Light mAttentionLight;
Mike Lockwood670f9322010-01-20 12:13:36 -0500234 private int mDefaultNotificationColor;
235 private int mDefaultNotificationLedOn;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800236
Mike Lockwood670f9322010-01-20 12:13:36 -0500237 private int mDefaultNotificationLedOff;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800238 private long[] mDefaultVibrationPattern;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800239
Daniel Sandleredbb3802012-11-13 20:49:47 -0800240 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400241 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800242 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800243
John Spurlockd8afe3c2014-08-01 14:04:07 -0400244 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400245 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500246 private String mSoundNotificationKey;
247 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
John Spurlockd8afe3c2014-08-01 14:04:07 -0400249 private final ArraySet<ManagedServiceInfo> mListenersDisablingEffects = new ArraySet<>();
John Spurlockb4782522014-08-22 14:54:46 -0400250 private ComponentName mEffectsSuppressor;
John Spurlockd8afe3c2014-08-01 14:04:07 -0400251 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500252 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400253
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500254 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400255 private boolean mScreenOn = true;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500256 private boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500257 private boolean mNotificationPulseEnabled;
258
Daniel Sandler09a247e2013-02-14 10:24:17 -0500259 // used as a mutex for access to all active notifications & listeners
Adam Lesinski182f73f2013-12-05 16:48:06 -0800260 final ArrayList<NotificationRecord> mNotificationList =
Fred Quintana6ecaff12009-09-25 14:23:13 -0700261 new ArrayList<NotificationRecord>();
John Spurlocka4294292014-03-24 18:02:32 -0400262 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
263 new ArrayMap<String, NotificationRecord>();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800264 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
Christoph Studer265c1052014-07-23 17:14:33 +0200265 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
John Spurlock7c74f782015-06-04 13:01:42 -0400266 final PolicyAccess mPolicyAccess = new PolicyAccess();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267
Chris Wren6054e612014-11-25 17:16:46 -0500268 // The last key in this list owns the hardware.
269 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700270
Adam Lesinski182f73f2013-12-05 16:48:06 -0800271 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700272 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500273
Griff Hazen9f637d12014-06-10 11:13:51 -0700274 private Archive mArchive;
275
John Spurlock21258a32015-05-27 18:22:55 -0400276 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400277 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400278
279 // Temporary holder for <blocked-packages> config coming from old policy files.
Daniel Sandler0da673f2012-04-11 12:33:16 -0400280 private HashSet<String> mBlockedPackages = new HashSet<String>();
281
282 private static final int DB_VERSION = 1;
283
John Spurlock21258a32015-05-27 18:22:55 -0400284 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400285 private static final String ATTR_VERSION = "version";
286
John Spurlock21258a32015-05-27 18:22:55 -0400287 // Obsolete: converted if present, but not resaved to disk.
Daniel Sandler0da673f2012-04-11 12:33:16 -0400288 private static final String TAG_BLOCKED_PKGS = "blocked-packages";
289 private static final String TAG_PACKAGE = "package";
290 private static final String ATTR_NAME = "name";
291
Chris Wren54bbef42014-07-09 18:37:56 -0400292 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400293
John Spurlockb408e8e2014-04-23 21:12:45 -0400294 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400295 private NotificationListeners mListeners;
Chris Wren51017d02015-12-15 15:34:46 -0500296 private NotificationAssistant mAssistant;
John Spurlock7340fc82014-04-24 18:50:12 -0400297 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200298 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100299
John Spurlocke6a7d932014-03-13 12:29:00 -0400300 private static final int MY_UID = Process.myUid();
301 private static final int MY_PID = Process.myPid();
Chris Wren51017d02015-12-15 15:34:46 -0500302 private RankingHandler mRankingHandler;
Chris Wren47633422016-01-22 09:56:59 -0500303 private Handler mAssistantHandler;
John Spurlocke6a7d932014-03-13 12:29:00 -0400304
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500305 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700306 final int mBufferSize;
307 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500308
Griff Hazen9f637d12014-06-10 11:13:51 -0700309 public Archive(int size) {
310 mBufferSize = size;
311 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500312 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700313
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400314 public String toString() {
315 final StringBuilder sb = new StringBuilder();
316 final int N = mBuffer.size();
317 sb.append("Archive (");
318 sb.append(N);
319 sb.append(" notification");
320 sb.append((N==1)?")":"s)");
321 return sb.toString();
322 }
323
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500324 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700325 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500326 mBuffer.removeFirst();
327 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400328
329 // We don't want to store the heavy bits of the notification in the archive,
330 // but other clients in the system process might be using the object, so we
331 // store a (lightened) copy.
332 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500333 }
334
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500335 public Iterator<StatusBarNotification> descendingIterator() {
336 return mBuffer.descendingIterator();
337 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500338
339 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700340 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500341 final StatusBarNotification[] a
342 = new StatusBarNotification[Math.min(count, mBuffer.size())];
343 Iterator<StatusBarNotification> iter = descendingIterator();
344 int i=0;
345 while (iter.hasNext() && i < count) {
346 a[i++] = iter.next();
347 }
348 return a;
349 }
350
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500351 }
352
John Spurlock35ef0a62015-05-28 11:24:10 -0400353 private void readPolicyXml(InputStream stream, boolean forRestore)
354 throws XmlPullParserException, NumberFormatException, IOException {
355 final XmlPullParser parser = Xml.newPullParser();
356 parser.setInput(stream, StandardCharsets.UTF_8.name());
357
358 int type;
359 String tag;
360 int version = DB_VERSION;
361 while ((type = parser.next()) != END_DOCUMENT) {
362 tag = parser.getName();
363 if (type == START_TAG) {
364 if (TAG_NOTIFICATION_POLICY.equals(tag)) {
365 version = Integer.parseInt(
366 parser.getAttributeValue(null, ATTR_VERSION));
367 } else if (TAG_BLOCKED_PKGS.equals(tag)) {
368 while ((type = parser.next()) != END_DOCUMENT) {
369 tag = parser.getName();
370 if (TAG_PACKAGE.equals(tag)) {
371 mBlockedPackages.add(
372 parser.getAttributeValue(null, ATTR_NAME));
373 } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
374 break;
375 }
376 }
377 }
378 }
379 mZenModeHelper.readXml(parser, forRestore);
380 mRankingHelper.readXml(parser, forRestore);
381 }
382 }
383
John Spurlock056c5192014-04-20 21:52:01 -0400384 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400385 if (DBG) Slog.d(TAG, "loadPolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400386 synchronized(mPolicyFile) {
387 mBlockedPackages.clear();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400388
John Spurlock056c5192014-04-20 21:52:01 -0400389 FileInputStream infile = null;
390 try {
391 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400392 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400393 } catch (FileNotFoundException e) {
394 // No data yet
395 } catch (IOException e) {
396 Log.wtf(TAG, "Unable to read notification policy", e);
397 } catch (NumberFormatException e) {
398 Log.wtf(TAG, "Unable to parse notification policy", e);
399 } catch (XmlPullParserException e) {
400 Log.wtf(TAG, "Unable to parse notification policy", e);
401 } finally {
402 IoUtils.closeQuietly(infile);
403 }
404 }
405 }
406
407 public void savePolicyFile() {
408 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
409 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
410 }
411
412 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400413 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400414 synchronized (mPolicyFile) {
415 final FileOutputStream stream;
416 try {
417 stream = mPolicyFile.startWrite();
418 } catch (IOException e) {
419 Slog.w(TAG, "Failed to save policy file", e);
420 return;
421 }
422
423 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400424 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400425 mPolicyFile.finishWrite(stream);
426 } catch (IOException e) {
427 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
428 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400429 }
430 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400431 BackupManager.dataChanged(getContext().getPackageName());
432 }
433
434 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
435 final XmlSerializer out = new FastXmlSerializer();
436 out.setOutput(stream, StandardCharsets.UTF_8.name());
437 out.startDocument(null, true);
438 out.startTag(null, TAG_NOTIFICATION_POLICY);
439 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
440 mZenModeHelper.writeXml(out, forBackup);
441 mRankingHelper.writeXml(out, forBackup);
442 out.endTag(null, TAG_NOTIFICATION_POLICY);
443 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400444 }
445
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500446 /** Use this when you actually want to post a notification or toast.
447 *
448 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
449 */
450 private boolean noteNotificationOp(String pkg, int uid) {
451 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
452 != AppOpsManager.MODE_ALLOWED) {
453 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
454 return false;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400455 }
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500456 return true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400457 }
458
Chris Wren66189fc2015-06-25 14:04:33 -0400459 /** Use this to check if a package can post a notification or toast. */
460 private boolean checkNotificationOp(String pkg, int uid) {
461 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000462 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
Chris Wren66189fc2015-06-25 14:04:33 -0400463 }
464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 private static final class ToastRecord
466 {
467 final int pid;
468 final String pkg;
469 final ITransientNotification callback;
470 int duration;
471
472 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
473 {
474 this.pid = pid;
475 this.pkg = pkg;
476 this.callback = callback;
477 this.duration = duration;
478 }
479
480 void update(int duration) {
481 this.duration = duration;
482 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800483
John Spurlock25e2d242014-06-27 13:58:23 -0400484 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
485 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 pw.println(prefix + this);
487 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 @Override
490 public final String toString()
491 {
492 return "ToastRecord{"
493 + Integer.toHexString(System.identityHashCode(this))
494 + " pkg=" + pkg
495 + " callback=" + callback
496 + " duration=" + duration;
497 }
498 }
499
Adam Lesinski182f73f2013-12-05 16:48:06 -0800500 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501
Adam Lesinski182f73f2013-12-05 16:48:06 -0800502 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 public void onSetDisabled(int status) {
504 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400505 mDisableNotificationEffects =
506 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400507 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 // cancel whatever's going on
509 long identity = Binder.clearCallingIdentity();
510 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800511 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700512 if (player != null) {
513 player.stopAsync();
514 }
515 } catch (RemoteException e) {
516 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 Binder.restoreCallingIdentity(identity);
518 }
519
520 identity = Binder.clearCallingIdentity();
521 try {
522 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700523 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800524 Binder.restoreCallingIdentity(identity);
525 }
526 }
527 }
528 }
529
Adam Lesinski182f73f2013-12-05 16:48:06 -0800530 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400531 public void onClearAll(int callingUid, int callingPid, int userId) {
Adam Lesinskie8240262014-03-26 16:01:00 -0700532 synchronized (mNotificationList) {
Kenny Guya263e4e2014-03-03 18:24:03 +0000533 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
534 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700535 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 }
537
Adam Lesinski182f73f2013-12-05 16:48:06 -0800538 @Override
Christoph Studer03b87a22014-04-30 17:33:27 +0200539 public void onNotificationClick(int callingUid, int callingPid, String key) {
540 synchronized (mNotificationList) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200541 NotificationRecord r = mNotificationsByKey.get(key);
542 if (r == null) {
543 Log.w(TAG, "No notification with key: " + key);
544 return;
545 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400546 final long now = System.currentTimeMillis();
547 EventLogTags.writeNotificationClicked(key,
548 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
549
Christoph Studer03b87a22014-04-30 17:33:27 +0200550 StatusBarNotification sbn = r.sbn;
551 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
552 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
553 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
554 REASON_DELEGATE_CLICK, null);
555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 }
557
Adam Lesinski182f73f2013-12-05 16:48:06 -0800558 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200559 public void onNotificationActionClick(int callingUid, int callingPid, String key,
560 int actionIndex) {
561 synchronized (mNotificationList) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200562 NotificationRecord r = mNotificationsByKey.get(key);
563 if (r == null) {
564 Log.w(TAG, "No notification with key: " + key);
565 return;
566 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400567 final long now = System.currentTimeMillis();
568 EventLogTags.writeNotificationActionClicked(key, actionIndex,
569 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Christoph Studer4da84cd2014-10-21 17:24:20 +0200570 // TODO: Log action click via UsageStats.
571 }
572 }
573
574 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400575 public void onNotificationClear(int callingUid, int callingPid,
576 String pkg, String tag, int id, int userId) {
577 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000578 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
John Spurlocke6a7d932014-03-13 12:29:00 -0400579 true, userId, REASON_DELEGATE_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400580 }
581
Adam Lesinski182f73f2013-12-05 16:48:06 -0800582 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400583 public void onPanelRevealed(boolean clearEffects, int items) {
584 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100585 if (clearEffects) {
586 clearEffects();
587 }
588 }
589
590 @Override
591 public void onPanelHidden() {
592 EventLogTags.writeNotificationPanelHidden();
593 }
594
595 @Override
596 public void clearEffects() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 synchronized (mNotificationList) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100598 if (DBG) Slog.d(TAG, "clearEffects");
599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 // sound
Chris Wren6054e612014-11-25 17:16:46 -0500601 mSoundNotificationKey = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700602
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 long identity = Binder.clearCallingIdentity();
604 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800605 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700606 if (player != null) {
607 player.stopAsync();
608 }
609 } catch (RemoteException e) {
610 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 Binder.restoreCallingIdentity(identity);
612 }
613
614 // vibrate
Chris Wren6054e612014-11-25 17:16:46 -0500615 mVibrateNotificationKey = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 identity = Binder.clearCallingIdentity();
617 try {
618 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700619 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 Binder.restoreCallingIdentity(identity);
621 }
622
623 // light
624 mLights.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 updateLightsLocked();
626 }
627 }
Joe Onorato005847b2010-06-04 16:08:02 -0400628
Adam Lesinski182f73f2013-12-05 16:48:06 -0800629 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400630 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000631 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400632 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
633 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400634 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
635 REASON_DELEGATE_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700636 long ident = Binder.clearCallingIdentity();
637 try {
638 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
639 "Bad notification posted from package " + pkg
640 + ": " + message);
641 } catch (RemoteException e) {
642 }
643 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400644 }
John Spurlocke677d712014-02-13 12:52:19 -0500645
646 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400647 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
648 NotificationVisibility[] noLongerVisibleKeys) {
Christoph Studerffeb0c32014-05-07 22:23:56 +0200649 synchronized (mNotificationList) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400650 for (NotificationVisibility nv : newlyVisibleKeys) {
651 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200652 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400653 r.setVisibility(true, nv.rank);
654 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200655 }
656 // Note that we might receive this event after notifications
657 // have already left the system, e.g. after dismissing from the
658 // shade. Hence not finding notifications in
659 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400660 for (NotificationVisibility nv : noLongerVisibleKeys) {
661 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200662 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400663 r.setVisibility(false, nv.rank);
664 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200665 }
666 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200667 }
Chris Wren78403d72014-07-28 10:23:24 +0100668
669 @Override
670 public void onNotificationExpansionChanged(String key,
671 boolean userAction, boolean expanded) {
Chris Wren78403d72014-07-28 10:23:24 +0100672 synchronized (mNotificationList) {
673 NotificationRecord r = mNotificationsByKey.get(key);
674 if (r != null) {
675 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400676 final long now = System.currentTimeMillis();
677 EventLogTags.writeNotificationExpansion(key,
678 userAction ? 1 : 0, expanded ? 1 : 0,
679 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100680 }
681 }
682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 };
684
Kenny Guy70058402014-10-28 20:45:06 +0000685 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 @Override
687 public void onReceive(Context context, Intent intent) {
688 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -0800689 if (action == null) {
690 return;
691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800693 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -0400694 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -0400695 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -0400696 boolean cancelNotifications = true;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000697 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -0400698
Chris Wren3da73022013-05-10 14:41:21 -0400699 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -0400700 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800701 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -0400702 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800703 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000704 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
705 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +0000706 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
707 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800708 String pkgList[] = null;
Chris Wrenae9bb572013-05-15 14:50:28 -0400709 boolean queryReplace = queryRemove &&
710 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
John Spurlocke77bb362014-04-26 10:24:59 -0400711 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800712 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800713 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000714 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
715 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
716 reason = REASON_PACKAGE_SUSPENDED;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800717 } else if (queryRestart) {
718 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800719 } else {
720 Uri uri = intent.getData();
721 if (uri == null) {
722 return;
723 }
724 String pkgName = uri.getSchemeSpecificPart();
725 if (pkgName == null) {
726 return;
727 }
Daniel Sandler26ece572012-06-01 15:38:46 -0400728 if (packageChanged) {
729 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -0700730 try {
Kenny Guy70058402014-10-28 20:45:06 +0000731 final IPackageManager pm = AppGlobals.getPackageManager();
732 final int enabled = pm.getApplicationEnabledSetting(pkgName,
733 changeUserId != UserHandle.USER_ALL ? changeUserId :
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700734 UserHandle.USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -0700735 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
736 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
737 cancelNotifications = false;
738 }
739 } catch (IllegalArgumentException e) {
740 // Package doesn't exist; probably racing with uninstall.
741 // cancelNotifications is already true, so nothing to do here.
742 if (DBG) {
743 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
744 }
Kenny Guy70058402014-10-28 20:45:06 +0000745 } catch (RemoteException e) {
746 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -0400747 }
748 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800749 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 }
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700751
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800752 if (pkgList != null && (pkgList.length > 0)) {
753 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -0400754 if (cancelNotifications) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400755 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500756 changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -0400757 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800758 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 }
John Spurlockb408e8e2014-04-23 21:12:45 -0400760 mListeners.onPackagesChanged(queryReplace, pkgList);
Chris Wren51017d02015-12-15 15:34:46 -0500761 mAssistant.onPackagesChanged(queryReplace, pkgList);
John Spurlock7340fc82014-04-24 18:50:12 -0400762 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
John Spurlock35ef0a62015-05-28 11:24:10 -0400763 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
Kenny Guy70058402014-10-28 20:45:06 +0000764 }
765 }
766 };
767
768 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
769 @Override
770 public void onReceive(Context context, Intent intent) {
771 String action = intent.getAction();
772
773 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400774 // Keep track of screen on/off state, but do not turn off the notification light
775 // until user passes through the lock screen or views the notification.
776 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +0100777 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400778 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
779 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +0100780 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500781 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -0500782 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
783 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500784 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700785 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
786 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
787 if (userHandle >= 0) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400788 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500789 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700790 }
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000791 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) {
792 boolean inQuietMode = intent.getBooleanExtra(Intent.EXTRA_QUIET_MODE, false);
793 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
794 if (inQuietMode && userHandle >= 0) {
795 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500796 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000797 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400798 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
799 // turn off LED when user passes through lock screen
800 mNotificationLight.turnOff();
John Spurlockcb566aa2014-08-03 22:58:28 -0400801 mStatusBar.notificationLightOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400802 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
John Spurlock1b8b22b2015-05-20 09:47:13 -0400803 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400804 // reload per-user settings
805 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -0400806 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200807 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -0400808 mConditionProviders.onUserSwitched(user);
809 mListeners.onUserSwitched(user);
Chris Wren51017d02015-12-15 15:34:46 -0500810 mAssistant.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -0400811 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000812 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
John Spurlockb408e8e2014-04-23 21:12:45 -0400813 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -0400814 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
815 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
816 mZenModeHelper.onUserRemoved(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500817 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
818 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
819 mConditionProviders.onUserUnlocked(user);
820 mListeners.onUserUnlocked(user);
821 mAssistant.onUserUnlocked(user);
822 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 }
824 }
825 };
826
John Spurlock7c74f782015-06-04 13:01:42 -0400827 private final class SettingsObserver extends ContentObserver {
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400828 private final Uri NOTIFICATION_LIGHT_PULSE_URI
829 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
830
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700831 SettingsObserver(Handler handler) {
832 super(handler);
833 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800834
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700835 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800836 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400837 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700838 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400839 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700840 }
841
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400842 @Override public void onChange(boolean selfChange, Uri uri) {
843 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700844 }
845
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400846 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800847 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400848 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
849 boolean pulseEnabled = Settings.System.getInt(resolver,
850 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
851 if (mNotificationPulseEnabled != pulseEnabled) {
852 mNotificationPulseEnabled = pulseEnabled;
853 updateNotificationPulse();
854 }
855 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700856 }
857 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500858
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800859 private final class NotificationVrListener extends VrStateListener {
860 @Override
861 public void onVrStateChanged(final boolean enabled) {
862 mListeners.setCategoryState(NotificationListenerService.CATEGORY_VR_NOTIFICATIONS,
863 enabled);
864 }
865 }
866
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400867 private SettingsObserver mSettingsObserver;
John Spurlock056c5192014-04-20 21:52:01 -0400868 private ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400869
John Spurlockcad57682014-07-26 17:09:56 -0400870 private final Runnable mBuzzBeepBlinked = new Runnable() {
871 @Override
872 public void run() {
873 mStatusBar.buzzBeepBlinked();
874 }
875 };
876
Daniel Sandleredbb3802012-11-13 20:49:47 -0800877 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
878 int[] ar = r.getIntArray(resid);
879 if (ar == null) {
880 return def;
881 }
882 final int len = ar.length > maxlen ? maxlen : ar.length;
883 long[] out = new long[len];
884 for (int i=0; i<len; i++) {
885 out[i] = ar[i];
886 }
887 return out;
888 }
889
Jeff Brownb880d882014-02-10 19:47:07 -0800890 public NotificationManagerService(Context context) {
891 super(context);
892 }
893
Adam Lesinski182f73f2013-12-05 16:48:06 -0800894 @Override
895 public void onStart() {
Chris Wren54bbef42014-07-09 18:37:56 -0400896 Resources resources = getContext().getResources();
897
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898 mAm = ActivityManagerNative.getDefault();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800899 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
900 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700901 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
San Mehat3ee13172010-02-04 20:54:43 -0800902
Adam Lesinski182f73f2013-12-05 16:48:06 -0800903 mHandler = new WorkerHandler();
Chris Wrenf9536642014-04-17 10:01:54 -0400904 mRankingThread.start();
Chris Wren47633422016-01-22 09:56:59 -0500905 mAssistantThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -0400906 String[] extractorNames;
907 try {
908 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
909 } catch (Resources.NotFoundException e) {
910 extractorNames = new String[0];
911 }
Chris Wren5eab2b72015-06-16 13:56:22 -0400912 mUsageStats = new NotificationUsageStats(getContext());
Chris Wren51017d02015-12-15 15:34:46 -0500913 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Chris Wren47633422016-01-22 09:56:59 -0500914 mAssistantHandler = new Handler(mAssistantThread.getLooper());
Chris Wren54bbef42014-07-09 18:37:56 -0400915 mRankingHelper = new RankingHelper(getContext(),
Chris Wren51017d02015-12-15 15:34:46 -0500916 mRankingHandler,
Chris Wren5eab2b72015-06-16 13:56:22 -0400917 mUsageStats,
Chris Wren54bbef42014-07-09 18:37:56 -0400918 extractorNames);
John Spurlockb2278d62015-04-07 12:47:12 -0400919 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
920 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -0400921 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -0400922 @Override
923 public void onConfigChanged() {
924 savePolicyFile();
925 }
John Spurlockd8afe3c2014-08-01 14:04:07 -0400926
927 @Override
928 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -0400929 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -0500930 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -0500931 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
932 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -0500933 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400934 synchronized(mNotificationList) {
Christoph Studer85a384b2014-08-27 20:16:15 +0200935 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400936 }
937 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400938
939 @Override
940 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -0400941 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
942 }
John Spurlock056c5192014-04-20 21:52:01 -0400943 });
944 final File systemDir = new File(Environment.getDataDirectory(), "system");
945 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500946
947 importOldBlockDb();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400948
John Spurlock7340fc82014-04-24 18:50:12 -0400949 mListeners = new NotificationListeners();
Chris Wren51017d02015-12-15 15:34:46 -0500950 mAssistant = new NotificationAssistant();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800951 mStatusBar = getLocalService(StatusBarManagerInternal.class);
952 mStatusBar.setNotificationDelegate(mNotificationDelegate);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953
Adam Lesinski182f73f2013-12-05 16:48:06 -0800954 final LightsManager lights = getLocalService(LightsManager.class);
955 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
956 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500957
Mike Lockwood670f9322010-01-20 12:13:36 -0500958 mDefaultNotificationColor = resources.getColor(
Scott Greenwald9a05b312013-06-28 00:37:54 -0400959 R.color.config_defaultNotificationColor);
Mike Lockwood670f9322010-01-20 12:13:36 -0500960 mDefaultNotificationLedOn = resources.getInteger(
Scott Greenwald9a05b312013-06-28 00:37:54 -0400961 R.integer.config_defaultNotificationLedOn);
Mike Lockwood670f9322010-01-20 12:13:36 -0500962 mDefaultNotificationLedOff = resources.getInteger(
Scott Greenwald9a05b312013-06-28 00:37:54 -0400963 R.integer.config_defaultNotificationLedOff);
Mike Lockwood670f9322010-01-20 12:13:36 -0500964
Daniel Sandleredbb3802012-11-13 20:49:47 -0800965 mDefaultVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -0400966 R.array.config_defaultNotificationVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -0800967 VIBRATE_PATTERN_MAXLEN,
968 DEFAULT_VIBRATE_PATTERN);
969
970 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -0400971 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -0800972 VIBRATE_PATTERN_MAXLEN,
973 DEFAULT_VIBRATE_PATTERN);
974
Chris Wren5116a822014-06-04 15:59:50 -0400975 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
976
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400977 // Don't start allowing notifications until the setup wizard has run once.
978 // After that, including subsequent boots, init with notifications turned on.
979 // This works on the first boot because the setup wizard will toggle this
980 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -0800981 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700982 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400983 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400984 }
John Spurlockb2278d62015-04-07 12:47:12 -0400985 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -0500986 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -0400987
John Spurlockb408e8e2014-04-23 21:12:45 -0400988 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -0400989 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +0000990
Mike Lockwood35e16bf2010-11-30 19:53:36 -0500991 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500993 filter.addAction(Intent.ACTION_SCREEN_ON);
994 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500995 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400996 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700997 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400998 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000999 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001000 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001001 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001002 filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001003 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001004
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001005 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001006 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001007 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001008 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001009 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1010 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1011 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001012 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1013 null);
1014
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001015 IntentFilter suspendedPkgFilter = new IntentFilter();
1016 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1017 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1018 suspendedPkgFilter, null, null);
1019
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001020 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001021 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1022 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001023
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001024 mSettingsObserver = new SettingsObserver(mHandler);
Scott Greenwald9a05b312013-06-28 00:37:54 -04001025
Griff Hazen9f637d12014-06-10 11:13:51 -07001026 mArchive = new Archive(resources.getInteger(
1027 R.integer.config_notificationServiceArchiveSize));
1028
Adam Lesinski182f73f2013-12-05 16:48:06 -08001029 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1030 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 }
1032
John Spurlocke7a835b2015-05-13 10:47:05 -04001033 private void sendRegisteredOnlyBroadcast(String action) {
1034 getContext().sendBroadcastAsUser(new Intent(action)
1035 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1036 }
1037
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001038 /**
1039 * Read the old XML-based app block database and import those blockages into the AppOps system.
1040 */
1041 private void importOldBlockDb() {
John Spurlock056c5192014-04-20 21:52:01 -04001042 loadPolicyFile();
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001043
Adam Lesinski182f73f2013-12-05 16:48:06 -08001044 PackageManager pm = getContext().getPackageManager();
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001045 for (String pkg : mBlockedPackages) {
1046 PackageInfo info = null;
1047 try {
1048 info = pm.getPackageInfo(pkg, 0);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001049 setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001050 } catch (NameNotFoundException e) {
1051 // forget you
1052 }
1053 }
1054 mBlockedPackages.clear();
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001055 }
1056
Adam Lesinski182f73f2013-12-05 16:48:06 -08001057 @Override
1058 public void onBootPhase(int phase) {
1059 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1060 // no beeping until we're basically done booting
1061 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001062
Adam Lesinski182f73f2013-12-05 16:48:06 -08001063 // Grab our optional AudioService
1064 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001065 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001066 mVrManagerInternal = getLocalService(VrManagerInternal.class);
1067 mVrManagerInternal.registerListener(mVrListener);
John Spurlock661f2cf2014-11-17 10:29:10 -05001068 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001069 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1070 // This observer will force an update when observe is called, causing us to
1071 // bind to listener services.
1072 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001073 mListeners.onBootPhaseAppsCanStart();
Chris Wren51017d02015-12-15 15:34:46 -05001074 mAssistant.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001075 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 }
1077 }
1078
Adam Lesinski182f73f2013-12-05 16:48:06 -08001079 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1080 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081
Adam Lesinski182f73f2013-12-05 16:48:06 -08001082 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1083 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084
Adam Lesinski182f73f2013-12-05 16:48:06 -08001085 // Now, cancel any outstanding notifications that are part of a just-disabled app
1086 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001087 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
Julia Reynoldsef37f282016-02-12 09:11:27 -05001088 REASON_PACKAGE_BANNED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090 }
1091
John Spurlockd8afe3c2014-08-01 14:04:07 -04001092 private void updateListenerHintsLocked() {
Christoph Studer85a384b2014-08-27 20:16:15 +02001093 final int hints = mListenersDisablingEffects.isEmpty() ? 0 : HINT_HOST_DISABLE_EFFECTS;
John Spurlockd8afe3c2014-08-01 14:04:07 -04001094 if (hints == mListenerHints) return;
John Spurlocka7082992015-03-09 12:19:23 -04001095 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mListenersDisablingEffects.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001096 mListenerHints = hints;
1097 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001098 }
1099
John Spurlockb4782522014-08-22 14:54:46 -04001100 private void updateEffectsSuppressorLocked() {
1101 final ComponentName suppressor = !mListenersDisablingEffects.isEmpty()
1102 ? mListenersDisablingEffects.valueAt(0).component : null;
1103 if (Objects.equals(suppressor, mEffectsSuppressor)) return;
John Spurlocka7082992015-03-09 12:19:23 -04001104 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressor, suppressor);
John Spurlockb4782522014-08-22 14:54:46 -04001105 mEffectsSuppressor = suppressor;
John Spurlock8403b752014-12-10 12:47:01 -05001106 mZenModeHelper.setEffectsSuppressed(suppressor != null);
John Spurlocke7a835b2015-05-13 10:47:05 -04001107 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001108 }
1109
Christoph Studer85a384b2014-08-27 20:16:15 +02001110 private void updateInterruptionFilterLocked() {
1111 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1112 if (interruptionFilter == mInterruptionFilter) return;
1113 mInterruptionFilter = interruptionFilter;
1114 scheduleInterruptionFilterChanged(interruptionFilter);
1115 }
1116
Adam Lesinski182f73f2013-12-05 16:48:06 -08001117 private final IBinder mService = new INotificationManager.Stub() {
1118 // Toasts
1119 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001122 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001124 if (DBG) {
1125 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1126 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001128
1129 if (pkg == null || callback == null) {
1130 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1131 return ;
1132 }
1133
John Spurlock7340fc82014-04-24 18:50:12 -04001134 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001135 final boolean isPackageSuspended =
1136 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001137
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001138 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001139 || isPackageSuspended)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001140 if (!isSystemToast) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001141 Slog.e(TAG, "Suppressing toast from package " + pkg
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001142 + (isPackageSuspended
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001143 ? " due to package suspended by administrator."
1144 : " by user request."));
Adam Lesinski182f73f2013-12-05 16:48:06 -08001145 return;
1146 }
1147 }
1148
1149 synchronized (mToastQueue) {
1150 int callingPid = Binder.getCallingPid();
1151 long callingId = Binder.clearCallingIdentity();
1152 try {
1153 ToastRecord record;
1154 int index = indexOfToastLocked(pkg, callback);
1155 // If it's already in the queue, we update it in place, we don't
1156 // move it to the end of the queue.
1157 if (index >= 0) {
1158 record = mToastQueue.get(index);
1159 record.update(duration);
1160 } else {
1161 // Limit the number of toasts that any given package except the android
1162 // package can enqueue. Prevents DOS attacks and deals with leaks.
1163 if (!isSystemToast) {
1164 int count = 0;
1165 final int N = mToastQueue.size();
1166 for (int i=0; i<N; i++) {
1167 final ToastRecord r = mToastQueue.get(i);
1168 if (r.pkg.equals(pkg)) {
1169 count++;
1170 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1171 Slog.e(TAG, "Package has already posted " + count
1172 + " toasts. Not showing more. Package=" + pkg);
1173 return;
1174 }
1175 }
1176 }
1177 }
1178
1179 record = new ToastRecord(callingPid, pkg, callback, duration);
1180 mToastQueue.add(record);
1181 index = mToastQueue.size() - 1;
1182 keepProcessAliveLocked(callingPid);
1183 }
1184 // If it's at index 0, it's the current toast. It doesn't matter if it's
1185 // new or just been updated. Call back and tell it to show itself.
1186 // If the callback fails, this will remove it from the list, so don't
1187 // assume that it's valid after this.
1188 if (index == 0) {
1189 showNextToastLocked();
1190 }
1191 } finally {
1192 Binder.restoreCallingIdentity(callingId);
1193 }
1194 }
1195 }
1196
1197 @Override
1198 public void cancelToast(String pkg, ITransientNotification callback) {
1199 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1200
1201 if (pkg == null || callback == null) {
1202 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1203 return ;
1204 }
1205
1206 synchronized (mToastQueue) {
1207 long callingId = Binder.clearCallingIdentity();
1208 try {
1209 int index = indexOfToastLocked(pkg, callback);
1210 if (index >= 0) {
1211 cancelToastLocked(index);
1212 } else {
1213 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1214 + " callback=" + callback);
1215 }
1216 } finally {
1217 Binder.restoreCallingIdentity(callingId);
1218 }
1219 }
1220 }
1221
1222 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001223 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Adam Lesinski182f73f2013-12-05 16:48:06 -08001224 Notification notification, int[] idOut, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001225 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Adam Lesinski182f73f2013-12-05 16:48:06 -08001226 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1227 }
1228
1229 @Override
1230 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001231 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001232 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1233 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
1234 // Don't allow client applications to cancel foreground service notis.
John Spurlocke6a7d932014-03-13 12:29:00 -04001235 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Adam Lesinski182f73f2013-12-05 16:48:06 -08001236 Binder.getCallingUid() == Process.SYSTEM_UID
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001237 ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId,
Chris Wren9fa689f2015-11-20 16:44:53 -05001238 REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001239 }
1240
1241 @Override
1242 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001243 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001244
1245 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1246 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1247
1248 // Calling from user space, don't allow the canceling of actively
1249 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04001250 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1251 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001252 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001253 }
1254
1255 @Override
1256 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
John Spurlock7340fc82014-04-24 18:50:12 -04001257 checkCallerIsSystem();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001258
1259 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
1260 }
1261
1262 /**
1263 * Use this when you just want to know if notifications are OK for this package.
1264 */
1265 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001266 public boolean areNotificationsEnabled(String pkg) {
1267 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1268 }
1269
1270 /**
1271 * Use this when you just want to know if notifications are OK for this package.
1272 */
1273 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001274 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001275 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001276 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001277 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001278 }
1279
Chris Wren54bbef42014-07-09 18:37:56 -04001280 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001281 public void setPriority(String pkg, int uid, int priority) {
Julia Reynoldsdd3e86b2016-02-02 10:24:30 -05001282 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001283 mRankingHelper.setPriority(pkg, uid, priority);
Chris Wren54bbef42014-07-09 18:37:56 -04001284 savePolicyFile();
1285 }
1286
1287 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001288 public int getPriority(String pkg, int uid) {
Chris Wren54bbef42014-07-09 18:37:56 -04001289 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001290 return mRankingHelper.getPriority(pkg, uid);
Chris Wren54bbef42014-07-09 18:37:56 -04001291 }
1292
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001293 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001294 public void setVisibilityOverride(String pkg, int uid, int visibility) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001295 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001296 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001297 savePolicyFile();
1298 }
1299
1300 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001301 public int getVisibilityOverride(String pkg, int uid) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001302 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001303 return mRankingHelper.getVisibilityOverride(pkg, uid);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001304 }
1305
Julia Reynolds5d25ee72015-11-20 15:38:20 -05001306 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001307 public void setImportance(String pkg, int uid, int importance) {
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001308 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynoldsef37f282016-02-12 09:11:27 -05001309 setNotificationsEnabledForPackageImpl(pkg, uid,
1310 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1311 mRankingHelper.setImportance(pkg, uid, importance);
Julia Reynolds5d25ee72015-11-20 15:38:20 -05001312 savePolicyFile();
1313 }
1314
1315 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001316 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001317 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05001318 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001319 }
1320
1321 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001322 public int getImportance(String pkg, int uid) {
Julia Reynolds5d25ee72015-11-20 15:38:20 -05001323 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001324 return mRankingHelper.getImportance(pkg, uid);
Julia Reynoldsbe8fdee2015-12-18 09:04:34 -05001325 }
1326
Adam Lesinski182f73f2013-12-05 16:48:06 -08001327 /**
1328 * System-only API for getting a list of current (i.e. not cleared) notifications.
1329 *
1330 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04001331 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001332 */
1333 @Override
1334 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1335 // enforce() will ensure the calling uid has the correct permission
1336 getContext().enforceCallingOrSelfPermission(
1337 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1338 "NotificationManagerService.getActiveNotifications");
1339
1340 StatusBarNotification[] tmp = null;
1341 int uid = Binder.getCallingUid();
1342
1343 // noteOp will check to make sure the callingPkg matches the uid
1344 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1345 == AppOpsManager.MODE_ALLOWED) {
1346 synchronized (mNotificationList) {
1347 tmp = new StatusBarNotification[mNotificationList.size()];
1348 final int N = mNotificationList.size();
1349 for (int i=0; i<N; i++) {
1350 tmp[i] = mNotificationList.get(i).sbn;
1351 }
1352 }
1353 }
1354 return tmp;
1355 }
1356
1357 /**
Dan Sandler994349c2015-04-15 11:02:54 -04001358 * Public API for getting a list of current notifications for the calling package/uid.
1359 *
1360 * @returns A list of all the package's notifications, in natural order.
1361 */
1362 @Override
1363 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1364 int incomingUserId) {
1365 checkCallerIsSystemOrSameApp(pkg);
1366 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1367 Binder.getCallingUid(), incomingUserId, true, false,
1368 "getAppActiveNotifications", pkg);
1369
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08001370 final ArrayList<StatusBarNotification> list
1371 = new ArrayList<StatusBarNotification>(mNotificationList.size());
Dan Sandler994349c2015-04-15 11:02:54 -04001372
1373 synchronized (mNotificationList) {
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08001374 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04001375 for (int i = 0; i < N; i++) {
1376 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
1377 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
1378 // We could pass back a cloneLight() but clients might get confused and
1379 // try to send this thing back to notify() again, which would not work
1380 // very well.
1381 final StatusBarNotification sbnOut = new StatusBarNotification(
1382 sbn.getPackageName(),
1383 sbn.getOpPkg(),
1384 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1385 0, // hide score from apps
1386 sbn.getNotification().clone(),
1387 sbn.getUser(), sbn.getPostTime());
1388 list.add(sbnOut);
1389 }
1390 }
1391 }
1392
1393 return new ParceledListSlice<StatusBarNotification>(list);
1394 }
1395
1396 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08001397 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1398 *
1399 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1400 */
1401 @Override
1402 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1403 // enforce() will ensure the calling uid has the correct permission
1404 getContext().enforceCallingOrSelfPermission(
1405 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1406 "NotificationManagerService.getHistoricalNotifications");
1407
1408 StatusBarNotification[] tmp = null;
1409 int uid = Binder.getCallingUid();
1410
1411 // noteOp will check to make sure the callingPkg matches the uid
1412 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1413 == AppOpsManager.MODE_ALLOWED) {
1414 synchronized (mArchive) {
1415 tmp = mArchive.getArray(count);
1416 }
1417 }
1418 return tmp;
1419 }
1420
1421 /**
1422 * Register a listener binder directly with the notification manager.
1423 *
1424 * Only works with system callers. Apps should extend
1425 * {@link android.service.notification.NotificationListenerService}.
1426 */
1427 @Override
1428 public void registerListener(final INotificationListener listener,
1429 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02001430 enforceSystemOrSystemUI("INotificationManager.registerListener");
John Spurlock7340fc82014-04-24 18:50:12 -04001431 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001432 }
1433
1434 /**
1435 * Remove a listener binder directly
1436 */
1437 @Override
1438 public void unregisterListener(INotificationListener listener, int userid) {
John Spurlock7340fc82014-04-24 18:50:12 -04001439 mListeners.unregisterService(listener, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001440 }
1441
1442 /**
1443 * Allow an INotificationListener to simulate a "clear all" operation.
1444 *
1445 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1446 *
1447 * @param token The binder for the listener, to check that the caller is allowed
1448 */
1449 @Override
John Spurlocka4294292014-03-24 18:02:32 -04001450 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001451 final int callingUid = Binder.getCallingUid();
1452 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001453 long identity = Binder.clearCallingIdentity();
1454 try {
Adam Lesinskie8240262014-03-26 16:01:00 -07001455 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001456 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
John Spurlocka4294292014-03-24 18:02:32 -04001457 if (keys != null) {
1458 final int N = keys.length;
1459 for (int i = 0; i < N; i++) {
1460 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07001461 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00001462 final int userId = r.sbn.getUserId();
1463 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04001464 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00001465 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04001466 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00001467 }
Griff Hazen335e1f02014-09-11 14:49:31 -07001468 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1469 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1470 userId);
John Spurlocka4294292014-03-24 18:02:32 -04001471 }
1472 } else {
1473 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00001474 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04001475 }
Adam Lesinskie8240262014-03-26 16:01:00 -07001476 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001477 } finally {
1478 Binder.restoreCallingIdentity(identity);
1479 }
1480 }
1481
Chris Wrenab41eec2016-01-04 18:01:27 -05001482 /**
1483 * Handle request from an approved listener to re-enable itself.
1484 *
1485 * @param component The componenet to be re-enabled, caller must match package.
1486 */
1487 @Override
1488 public void requestBindListener(ComponentName component) {
1489 checkCallerIsSystemOrSameApp(component.getPackageName());
1490 long identity = Binder.clearCallingIdentity();
1491 try {
1492 ManagedServices manager = mAssistant.isComponentEnabledForCurrentProfiles(component)
1493 ? mAssistant
1494 : mListeners;
1495 manager.setComponentState(component, true);
1496 } finally {
1497 Binder.restoreCallingIdentity(identity);
1498 }
1499 }
1500
1501 @Override
1502 public void requestUnbindListener(INotificationListener token) {
1503 long identity = Binder.clearCallingIdentity();
1504 try {
1505 // allow bound services to disable themselves
1506 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1507 info.getOwner().setComponentState(info.component, false);
1508 } finally {
1509 Binder.restoreCallingIdentity(identity);
1510 }
1511 }
1512
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001513 @Override
1514 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001515 long identity = Binder.clearCallingIdentity();
1516 try {
1517 synchronized (mNotificationList) {
1518 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1519 if (keys != null) {
1520 final int N = keys.length;
1521 for (int i = 0; i < N; i++) {
1522 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1523 if (r == null) continue;
1524 final int userId = r.sbn.getUserId();
1525 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1526 !mUserProfiles.isCurrentProfile(userId)) {
1527 throw new SecurityException("Disallowed call from listener: "
1528 + info.service);
1529 }
1530 if (!r.isSeen()) {
1531 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1532 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07001533 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001534 : userId,
Adam Lesinskic8e87292015-06-10 15:33:45 -07001535 UsageEvents.Event.USER_INTERACTION);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001536 r.setSeen();
1537 }
1538 }
1539 }
1540 }
1541 } finally {
1542 Binder.restoreCallingIdentity(identity);
1543 }
1544 }
1545
John Spurlock7340fc82014-04-24 18:50:12 -04001546 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00001547 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04001548 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1549 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1550 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00001551 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04001552 }
1553
Adam Lesinski182f73f2013-12-05 16:48:06 -08001554 /**
1555 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1556 *
1557 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1558 *
1559 * @param token The binder for the listener, to check that the caller is allowed
1560 */
1561 @Override
1562 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1563 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001564 final int callingUid = Binder.getCallingUid();
1565 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001566 long identity = Binder.clearCallingIdentity();
1567 try {
Adam Lesinskie8240262014-03-26 16:01:00 -07001568 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001569 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00001570 if (info.supportsProfiles()) {
1571 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1572 + "from " + info.component
1573 + " use cancelNotification(key) instead.");
1574 } else {
1575 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1576 pkg, tag, id, info.userid);
1577 }
Adam Lesinskie8240262014-03-26 16:01:00 -07001578 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001579 } finally {
1580 Binder.restoreCallingIdentity(identity);
1581 }
1582 }
1583
1584 /**
1585 * Allow an INotificationListener to request the list of outstanding notifications seen by
1586 * the current user. Useful when starting up, after which point the listener callbacks
1587 * should be used.
1588 *
1589 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001590 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04001591 * @returns The return value will contain the notifications specified in keys, in that
1592 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001593 */
1594 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02001595 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02001596 INotificationListener token, String[] keys, int trim) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001597 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001598 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001599 final boolean getKeys = keys != null;
1600 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02001601 final ArrayList<StatusBarNotification> list
1602 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02001603 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001604 final NotificationRecord r = getKeys
1605 ? mNotificationsByKey.get(keys[i])
1606 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02001607 if (r == null) continue;
1608 StatusBarNotification sbn = r.sbn;
1609 if (!isVisibleToListener(sbn, info)) continue;
1610 StatusBarNotification sbnToSend =
1611 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1612 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001613 }
Christoph Studercee44ba2014-05-20 18:36:43 +02001614 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001615 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001616 }
1617
1618 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04001619 public void requestHintsFromListener(INotificationListener token, int hints) {
1620 final long identity = Binder.clearCallingIdentity();
1621 try {
1622 synchronized (mNotificationList) {
1623 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1624 final boolean disableEffects = (hints & HINT_HOST_DISABLE_EFFECTS) != 0;
1625 if (disableEffects) {
1626 mListenersDisablingEffects.add(info);
1627 } else {
1628 mListenersDisablingEffects.remove(info);
1629 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001630 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04001631 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04001632 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001633 } finally {
1634 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04001635 }
1636 }
1637
1638 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04001639 public int getHintsFromListener(INotificationListener token) {
John Spurlock1fa865f2014-07-21 14:56:39 -04001640 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001641 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04001642 }
1643 }
1644
1645 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02001646 public void requestInterruptionFilterFromListener(INotificationListener token,
1647 int interruptionFilter) throws RemoteException {
1648 final long identity = Binder.clearCallingIdentity();
1649 try {
1650 synchronized (mNotificationList) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001651 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1652 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02001653 updateInterruptionFilterLocked();
1654 }
1655 } finally {
1656 Binder.restoreCallingIdentity(identity);
1657 }
1658 }
1659
1660 @Override
1661 public int getInterruptionFilterFromListener(INotificationListener token)
1662 throws RemoteException {
1663 synchronized (mNotificationLight) {
1664 return mInterruptionFilter;
1665 }
1666 }
1667
1668 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02001669 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1670 throws RemoteException {
1671 synchronized (mNotificationList) {
1672 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1673 if (info == null) return;
1674 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1675 }
1676 }
1677
1678 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04001679 public int getZenMode() {
1680 return mZenModeHelper.getZenMode();
1681 }
1682
1683 @Override
John Spurlock056c5192014-04-20 21:52:01 -04001684 public ZenModeConfig getZenModeConfig() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001685 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04001686 return mZenModeHelper.getConfig();
1687 }
1688
1689 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04001690 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001691 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1692 final long identity = Binder.clearCallingIdentity();
1693 try {
John Spurlockb2278d62015-04-07 12:47:12 -04001694 mZenModeHelper.setManualZenMode(mode, conditionId, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001695 } finally {
1696 Binder.restoreCallingIdentity(identity);
1697 }
1698 }
1699
1700 @Override
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001701 public List<AutomaticZenRule> getAutomaticZenRules() throws RemoteException {
1702 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
1703 return mZenModeHelper.getAutomaticZenRules();
1704 }
1705
1706 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001707 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1708 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001709 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001710 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001711 }
1712
1713 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001714 public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001715 throws RemoteException {
1716 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1717 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1718 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1719 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001720 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001721
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001722 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1723 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001724 }
1725
1726 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001727 public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule)
1728 throws RemoteException {
1729 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1730 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1731 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1732 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1733 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001734
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001735 return mZenModeHelper.updateAutomaticZenRule(automaticZenRule,
1736 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001737 }
1738
1739 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001740 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1741 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001742 // Verify that they can modify zen rules.
1743 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1744
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001745 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001746 }
1747
1748 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05001749 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1750 Preconditions.checkNotNull(packageName, "Package name is null");
1751 enforceSystemOrSystemUI("removeAutomaticZenRules");
1752
1753 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1754 }
1755
1756 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05001757 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1758 Preconditions.checkNotNull(owner, "Owner is null");
1759 enforceSystemOrSystemUI("getRuleInstanceCount");
1760
1761 return mZenModeHelper.getCurrentInstanceCount(owner);
1762 }
1763
1764 @Override
John Spurlock80774932015-05-07 17:38:50 -04001765 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1766 enforcePolicyAccess(pkg, "setInterruptionFilter");
1767 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1768 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1769 final long identity = Binder.clearCallingIdentity();
1770 try {
1771 mZenModeHelper.setManualZenMode(zen, null, "setInterruptionFilter");
1772 } finally {
1773 Binder.restoreCallingIdentity(identity);
1774 }
1775 }
1776
1777 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04001778 public void notifyConditions(final String pkg, IConditionProvider provider,
1779 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04001780 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1781 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04001782 mHandler.post(new Runnable() {
1783 @Override
1784 public void run() {
1785 mConditionProviders.notifyConditions(pkg, info, conditions);
1786 }
1787 });
John Spurlocke77bb362014-04-26 10:24:59 -04001788 }
1789
John Spurlockcdb57ae2015-02-11 19:04:11 -05001790 private void enforceSystemOrSystemUIOrVolume(String message) {
1791 if (mAudioManagerInternal != null) {
1792 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1793 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1794 return;
1795 }
1796 }
1797 enforceSystemOrSystemUI(message);
1798 }
1799
John Spurlocke77bb362014-04-26 10:24:59 -04001800 private void enforceSystemOrSystemUI(String message) {
1801 if (isCallerSystem()) return;
1802 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1803 message);
John Spurlock7340fc82014-04-24 18:50:12 -04001804 }
1805
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001806 private void enforcePolicyAccess(int uid, String method) {
1807 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1808 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1809 return;
1810 }
1811 boolean accessAllowed = false;
1812 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1813 final int packageCount = packages.length;
1814 for (int i = 0; i < packageCount; i++) {
1815 if (checkPolicyAccess(packages[i])) {
1816 accessAllowed = true;
1817 }
1818 }
1819 if (!accessAllowed) {
1820 Slog.w(TAG, "Notification policy access denied calling " + method);
1821 throw new SecurityException("Notification policy access denied");
1822 }
1823 }
1824
John Spurlock80774932015-05-07 17:38:50 -04001825 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04001826 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1827 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1828 return;
1829 }
John Spurlock80774932015-05-07 17:38:50 -04001830 if (!checkPolicyAccess(pkg)) {
1831 Slog.w(TAG, "Notification policy access denied calling " + method);
1832 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04001833 }
1834 }
1835
John Spurlock80774932015-05-07 17:38:50 -04001836 private boolean checkPackagePolicyAccess(String pkg) {
John Spurlock7c74f782015-06-04 13:01:42 -04001837 return mPolicyAccess.isPackageGranted(pkg);
John Spurlock80774932015-05-07 17:38:50 -04001838 }
1839
1840 private boolean checkPolicyAccess(String pkg) {
1841 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04001842 }
1843
John Spurlock7340fc82014-04-24 18:50:12 -04001844 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001845 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1846 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1847 != PackageManager.PERMISSION_GRANTED) {
John Spurlock2b122f42014-08-27 16:29:47 -04001848 pw.println("Permission Denial: can't dump NotificationManager from pid="
Adam Lesinski182f73f2013-12-05 16:48:06 -08001849 + Binder.getCallingPid()
1850 + ", uid=" + Binder.getCallingUid());
1851 return;
1852 }
1853
Chris Wrene4b38802015-07-07 15:54:19 -04001854 final DumpFilter filter = DumpFilter.parseFromArguments(args);
1855 if (filter != null && filter.stats) {
1856 dumpJson(pw, filter);
1857 } else {
1858 dumpImpl(pw, filter);
1859 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001860 }
John Spurlockb4782522014-08-22 14:54:46 -04001861
1862 @Override
1863 public ComponentName getEffectsSuppressor() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001864 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
John Spurlockb4782522014-08-22 14:54:46 -04001865 return mEffectsSuppressor;
1866 }
John Spurlock2b122f42014-08-27 16:29:47 -04001867
1868 @Override
1869 public boolean matchesCallFilter(Bundle extras) {
1870 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02001871 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07001872 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02001873 extras,
1874 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
1875 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
1876 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04001877 }
John Spurlock530052a2014-11-30 16:26:19 -05001878
1879 @Override
1880 public boolean isSystemConditionProviderEnabled(String path) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001881 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04001882 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05001883 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001884
Christopher Tatef9767d62015-04-08 14:35:43 -07001885 // Backup/restore interface
1886 @Override
1887 public byte[] getBackupPayload(int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04001888 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07001889 //TODO: http://b/22388012
1890 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04001891 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
1892 return null;
1893 }
1894 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
1895 try {
1896 writePolicyXml(baos, true /*forBackup*/);
1897 return baos.toByteArray();
1898 } catch (IOException e) {
1899 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
1900 }
Christopher Tatef9767d62015-04-08 14:35:43 -07001901 return null;
1902 }
1903
1904 @Override
1905 public void applyRestore(byte[] payload, int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04001906 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
1907 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
1908 if (payload == null) {
1909 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
1910 return;
1911 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07001912 //TODO: http://b/22388012
1913 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04001914 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
1915 return;
1916 }
1917 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
1918 try {
1919 readPolicyXml(bais, true /*forRestore*/);
1920 savePolicyFile();
1921 } catch (NumberFormatException | XmlPullParserException | IOException e) {
1922 Slog.w(TAG, "applyRestore: error reading payload", e);
1923 }
Christopher Tatef9767d62015-04-08 14:35:43 -07001924 }
1925
John Spurlock1fc476d2015-04-14 16:05:20 -04001926 @Override
John Spurlock80774932015-05-07 17:38:50 -04001927 public boolean isNotificationPolicyAccessGranted(String pkg) {
1928 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04001929 }
1930
1931 @Override
John Spurlock80774932015-05-07 17:38:50 -04001932 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
1933 enforceSystemOrSystemUI("request policy access status for another package");
1934 return checkPackagePolicyAccess(pkg);
1935 }
1936
1937 @Override
1938 public String[] getPackagesRequestingNotificationPolicyAccess()
1939 throws RemoteException {
1940 enforceSystemOrSystemUI("request policy access packages");
1941 final long identity = Binder.clearCallingIdentity();
1942 try {
John Spurlock7c74f782015-06-04 13:01:42 -04001943 return mPolicyAccess.getRequestingPackages();
John Spurlock80774932015-05-07 17:38:50 -04001944 } finally {
1945 Binder.restoreCallingIdentity(identity);
1946 }
1947 }
1948
1949 @Override
1950 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
1951 throws RemoteException {
1952 enforceSystemOrSystemUI("grant notification policy access");
1953 final long identity = Binder.clearCallingIdentity();
1954 try {
1955 synchronized (mNotificationList) {
1956 mPolicyAccess.put(pkg, granted);
1957 }
1958 } finally {
1959 Binder.restoreCallingIdentity(identity);
1960 }
1961 }
1962
1963 @Override
1964 public Policy getNotificationPolicy(String pkg) {
1965 enforcePolicyAccess(pkg, "getNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04001966 final long identity = Binder.clearCallingIdentity();
1967 try {
1968 return mZenModeHelper.getNotificationPolicy();
1969 } finally {
1970 Binder.restoreCallingIdentity(identity);
1971 }
1972 }
1973
1974 @Override
John Spurlock80774932015-05-07 17:38:50 -04001975 public void setNotificationPolicy(String pkg, Policy policy) {
1976 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04001977 final long identity = Binder.clearCallingIdentity();
1978 try {
1979 mZenModeHelper.setNotificationPolicy(policy);
1980 } finally {
1981 Binder.restoreCallingIdentity(identity);
1982 }
1983 }
Chris Wren51017d02015-12-15 15:34:46 -05001984
1985 @Override
1986 public void setImportanceFromAssistant(INotificationListener token, String key,
Chris Wren47633422016-01-22 09:56:59 -05001987 int importance, CharSequence explanation) throws RemoteException {
Chris Wren4a4b49d2016-02-09 11:25:08 -05001988 if (importance == IMPORTANCE_NONE) {
1989 throw new IllegalArgumentException("blocking not allowed: key=" + key);
1990 }
Chris Wren51017d02015-12-15 15:34:46 -05001991 final long identity = Binder.clearCallingIdentity();
1992 try {
1993 synchronized (mNotificationList) {
1994 mAssistant.checkServiceTokenLocked(token);
1995 NotificationRecord n = mNotificationsByKey.get(key);
1996 n.setImportance(importance, explanation);
1997 mRankingHandler.requestSort();
1998 }
1999 } finally {
2000 Binder.restoreCallingIdentity(identity);
2001 }
2002 }
John Spurlock1fc476d2015-04-14 16:05:20 -04002003 };
John Spurlocka4294292014-03-24 18:02:32 -04002004
John Spurlock32fe4c62014-10-02 12:16:02 -04002005 private String disableNotificationEffects(NotificationRecord record) {
2006 if (mDisableNotificationEffects) {
2007 return "booleanState";
2008 }
2009 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2010 return "listenerHints";
2011 }
2012 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2013 return "callState";
2014 }
2015 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04002016 };
2017
2018 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2019 JSONObject dump = new JSONObject();
2020 try {
2021 dump.put("service", "Notification Manager");
2022 JSONArray bans = new JSONArray();
2023 try {
2024 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
2025 for (Integer userId : packageBans.keySet()) {
2026 for (String packageName : packageBans.get(userId)) {
2027 JSONObject ban = new JSONObject();
2028 ban.put("userId", userId);
2029 ban.put("packageName", packageName);
2030 bans.put(ban);
2031 }
2032 }
2033 } catch (NameNotFoundException e) {
2034 // pass
2035 }
2036 dump.put("bans", bans);
2037 dump.put("stats", mUsageStats.dumpJson(filter));
2038 } catch (JSONException e) {
2039 e.printStackTrace();
2040 }
2041 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04002042 }
2043
John Spurlock25e2d242014-06-27 13:58:23 -04002044 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2045 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04002046 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04002047 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04002048 }
2049 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08002050 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002051 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002052
John Spurlock50806fc2014-07-15 10:22:02 -04002053 if (!zenOnly) {
2054 synchronized (mToastQueue) {
2055 N = mToastQueue.size();
2056 if (N > 0) {
2057 pw.println(" Toast Queue:");
2058 for (int i=0; i<N; i++) {
2059 mToastQueue.get(i).dump(pw, " ", filter);
2060 }
2061 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002062 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002063 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002064 }
2065
2066 synchronized (mNotificationList) {
John Spurlock50806fc2014-07-15 10:22:02 -04002067 if (!zenOnly) {
2068 N = mNotificationList.size();
John Spurlock25e2d242014-06-27 13:58:23 -04002069 if (N > 0) {
John Spurlock50806fc2014-07-15 10:22:02 -04002070 pw.println(" Notification List:");
John Spurlock25e2d242014-06-27 13:58:23 -04002071 for (int i=0; i<N; i++) {
John Spurlock50806fc2014-07-15 10:22:02 -04002072 final NotificationRecord nr = mNotificationList.get(i);
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002073 if (filter.filtered && !filter.matches(nr.sbn)) continue;
Dan Sandlera1770312015-07-10 13:59:29 -04002074 nr.dump(pw, " ", getContext(), filter.redact);
John Spurlock25e2d242014-06-27 13:58:23 -04002075 }
2076 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002077 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002078
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002079 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04002080 N = mLights.size();
2081 if (N > 0) {
2082 pw.println(" Lights List:");
2083 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05002084 if (i == N - 1) {
2085 pw.print(" > ");
2086 } else {
2087 pw.print(" ");
2088 }
2089 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04002090 }
2091 pw.println(" ");
2092 }
John Spurlockcb566aa2014-08-03 22:58:28 -04002093 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2094 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05002095 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2096 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002097 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04002098 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04002099 pw.println(" mSystemReady=" + mSystemReady);
2100 }
2101 pw.println(" mArchive=" + mArchive.toString());
2102 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2103 int i=0;
2104 while (iter.hasNext()) {
2105 final StatusBarNotification sbn = iter.next();
2106 if (filter != null && !filter.matches(sbn)) continue;
2107 pw.println(" " + sbn);
2108 if (++i >= 5) {
2109 if (iter.hasNext()) pw.println(" ...");
2110 break;
2111 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002112 }
2113 }
2114
John Spurlock50806fc2014-07-15 10:22:02 -04002115 if (!zenOnly) {
2116 pw.println("\n Usage Stats:");
2117 mUsageStats.dump(pw, " ", filter);
2118 }
Christoph Studer546bec82014-03-14 12:17:12 +01002119
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002120 if (!filter.filtered || zenOnly) {
John Spurlock25e2d242014-06-27 13:58:23 -04002121 pw.println("\n Zen Mode:");
John Spurlockf3701772015-02-12 13:29:37 -05002122 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
John Spurlock25e2d242014-06-27 13:58:23 -04002123 mZenModeHelper.dump(pw, " ");
John Spurlock6ae82a72014-07-16 16:23:01 -04002124
2125 pw.println("\n Zen Log:");
2126 ZenLog.dump(pw, " ");
John Spurlock25e2d242014-06-27 13:58:23 -04002127 }
John Spurlocke77bb362014-04-26 10:24:59 -04002128
John Spurlock50806fc2014-07-15 10:22:02 -04002129 if (!zenOnly) {
2130 pw.println("\n Ranking Config:");
2131 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04002132
John Spurlock50806fc2014-07-15 10:22:02 -04002133 pw.println("\n Notification listeners:");
2134 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002135 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2136 pw.print(" mListenersDisablingEffects: (");
2137 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04002138 for (int i = 0; i < N; i++) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002139 final ManagedServiceInfo listener = mListenersDisablingEffects.valueAt(i);
John Spurlock1fa865f2014-07-21 14:56:39 -04002140 if (i > 0) pw.print(',');
2141 pw.print(listener.component);
2142 }
2143 pw.println(')');
Chris Wren51017d02015-12-15 15:34:46 -05002144 pw.println("\n Notification assistant:");
2145 mAssistant.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04002146 }
John Spurlock80774932015-05-07 17:38:50 -04002147 pw.println("\n Policy access:");
2148 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
John Spurlocke77bb362014-04-26 10:24:59 -04002149
2150 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04002151 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02002152
2153 pw.println("\n Group summaries:");
2154 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2155 NotificationRecord r = entry.getValue();
2156 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2157 if (mNotificationsByKey.get(r.getKey()) != r) {
2158 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04002159 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02002160 }
2161 }
Chris Wren66189fc2015-06-25 14:04:33 -04002162
2163 try {
2164 pw.println("\n Banned Packages:");
Chris Wrene4b38802015-07-07 15:54:19 -04002165 ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
2166 for (Integer userId : packageBans.keySet()) {
2167 for (String packageName : packageBans.get(userId)) {
2168 pw.println(" " + userId + ": " + packageName);
Chris Wren66189fc2015-06-25 14:04:33 -04002169 }
2170 }
2171 } catch (NameNotFoundException e) {
2172 // pass
2173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 }
2175 }
2176
Chris Wrene4b38802015-07-07 15:54:19 -04002177 private ArrayMap<Integer, ArrayList<String>> getPackageBans(DumpFilter filter)
2178 throws NameNotFoundException {
2179 ArrayMap<Integer, ArrayList<String>> packageBans = new ArrayMap<>();
2180 ArrayList<String> packageNames = new ArrayList<>();
2181 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
2182 final int userId = user.getUserHandle().getIdentifier();
2183 final PackageManager packageManager = getContext().getPackageManager();
Jeff Sharkeye06b4d12016-01-06 14:51:50 -07002184 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
Chris Wrene4b38802015-07-07 15:54:19 -04002185 final int packageCount = packages.size();
2186 for (int p = 0; p < packageCount; p++) {
2187 final String packageName = packages.get(p).packageName;
2188 if (filter == null || filter.matches(packageName)) {
Jeff Sharkeye06b4d12016-01-06 14:51:50 -07002189 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
Chris Wrene4b38802015-07-07 15:54:19 -04002190 if (!checkNotificationOp(packageName, uid)) {
2191 packageNames.add(packageName);
2192 }
2193 }
2194 }
2195 if (!packageNames.isEmpty()) {
2196 packageBans.put(userId, packageNames);
2197 packageNames = new ArrayList<>();
2198 }
2199 }
2200 return packageBans;
2201 }
2202
Adam Lesinski182f73f2013-12-05 16:48:06 -08002203 /**
2204 * The private API only accessible to the system process.
2205 */
2206 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2207 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002208 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002209 String tag, int id, Notification notification, int[] idReceived, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002210 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002211 idReceived, userId);
2212 }
Christoph Studer365e4c32014-09-18 20:35:36 +02002213
2214 @Override
2215 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2216 int userId) {
2217 checkCallerIsSystem();
2218 synchronized (mNotificationList) {
2219 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2220 if (i < 0) {
2221 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2222 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2223 return;
2224 }
2225 NotificationRecord r = mNotificationList.get(i);
2226 StatusBarNotification sbn = r.sbn;
2227 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2228 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2229 // we have to revert to the flags we received initially *and* force remove
2230 // FLAG_FOREGROUND_SERVICE.
2231 sbn.getNotification().flags =
2232 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2233 mRankingHelper.sort(mNotificationList);
2234 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2235 }
2236 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002237 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002238
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002239 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04002240 final int callingPid, final String tag, final int id, final Notification notification,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002241 int[] idOut, int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04002242 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002243 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2244 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04002245 }
John Spurlock7340fc82014-04-24 18:50:12 -04002246 checkCallerIsSystemOrSameApp(pkg);
2247 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
Justin Koh38156c52014-06-04 13:57:49 -07002248 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002249
Scott Greenwald9b05c612013-06-25 23:44:05 -04002250 final int userId = ActivityManager.handleIncomingUser(callingPid,
2251 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07002252 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07002253
Joe Onoratobd73d012010-06-04 11:44:54 -07002254 // Limit the number of notifications that any given package except the android
Justin Koh38156c52014-06-04 13:57:49 -07002255 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2256 if (!isSystemNotification && !isNotificationFromListener) {
Joe Onoratobd73d012010-06-04 11:44:54 -07002257 synchronized (mNotificationList) {
2258 int count = 0;
2259 final int N = mNotificationList.size();
2260 for (int i=0; i<N; i++) {
2261 final NotificationRecord r = mNotificationList.get(i);
Daniel Sandler4f91efd2013-04-25 16:38:41 -04002262 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
Vladimir Marko2526f332013-09-11 11:13:55 +01002263 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2264 break; // Allow updating existing notification
2265 }
Joe Onoratobd73d012010-06-04 11:44:54 -07002266 count++;
2267 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2268 Slog.e(TAG, "Package has already posted " + count
2269 + " notifications. Not showing more. package=" + pkg);
2270 return;
2271 }
2272 }
2273 }
2274 }
2275 }
2276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 if (pkg == null || notification == null) {
2278 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2279 + " id=" + id + " notification=" + notification);
2280 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04002281
Chris Wren47633422016-01-22 09:56:59 -05002282 // Sanitize inputs
2283 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2284 Notification.PRIORITY_MAX);
Daniel Sandler0da673f2012-04-11 12:33:16 -04002285
Chris Wren47633422016-01-22 09:56:59 -05002286 // setup local book-keeping
2287 final StatusBarNotification n = new StatusBarNotification(
2288 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2289 user);
2290 final NotificationRecord r = new NotificationRecord(getContext(), n);
2291 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292
2293 idOut[0] = id;
2294 }
2295
Chris Wren47633422016-01-22 09:56:59 -05002296 private class EnqueueNotificationRunnable implements Runnable {
2297 private final NotificationRecord r;
2298 private final int userId;
2299
2300 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2301 this.userId = userId;
2302 this.r = r;
2303 };
2304
2305 @Override
2306 public void run() {
2307
2308 synchronized (mNotificationList) {
2309 final StatusBarNotification n = r.sbn;
Chris Wren1ac52a92016-02-24 14:54:52 -05002310 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
Chris Wren47633422016-01-22 09:56:59 -05002311 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2312 if (old != null) {
2313 // Retain ranking information from previous record
2314 r.copyRankingInformation(old);
2315 }
2316
2317 final int callingUid = n.getUid();
2318 final int callingPid = n.getInitialPid();
2319 final Notification notification = n.getNotification();
2320 final String pkg = n.getPackageName();
2321 final int id = n.getId();
2322 final String tag = n.getTag();
2323 final boolean isSystemNotification = isUidSystem(callingUid) ||
2324 ("android".equals(pkg));
2325
2326 // Handle grouped notifications and bail out early if we
2327 // can to avoid extracting signals.
2328 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
2329 boolean ignoreNotification =
2330 removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
Chris Wren1ac52a92016-02-24 14:54:52 -05002331 if (DBG) Slog.d(TAG, "ignoreNotification is " + ignoreNotification);
Chris Wren47633422016-01-22 09:56:59 -05002332
2333 // This conditional is a dirty hack to limit the logging done on
2334 // behalf of the download manager without affecting other apps.
2335 if (!pkg.equals("com.android.providers.downloads")
2336 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2337 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
2338 if (ignoreNotification) {
2339 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED;
2340 } else if (old != null) {
2341 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2342 }
2343 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2344 pkg, id, tag, userId, notification.toString(),
2345 enqueueStatus);
2346 }
2347
2348 if (ignoreNotification) {
2349 return;
2350 }
2351
2352 mRankingHelper.extractSignals(r);
2353
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002354 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
Chris Wren47633422016-01-22 09:56:59 -05002355
Julia Reynoldsef37f282016-02-12 09:11:27 -05002356 // blocked apps
Chris Wren47633422016-01-22 09:56:59 -05002357 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002358 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
Chris Wren47633422016-01-22 09:56:59 -05002359 if (!isSystemNotification) {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002360 if (isPackageSuspended) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00002361 Slog.e(TAG, "Suppressing notification from package due to package "
2362 + "suspended by administrator.");
2363 mUsageStats.registerSuspendedByAdmin(r);
2364 } else {
2365 Slog.e(TAG, "Suppressing notification from package by user request.");
2366 mUsageStats.registerBlocked(r);
2367 }
Chris Wren47633422016-01-22 09:56:59 -05002368 return;
2369 }
2370 }
2371
2372 // tell the assistant about the notification
2373 if (mAssistant.isEnabled()) {
2374 mAssistant.onNotificationEnqueued(r);
2375 // TODO delay the code below here for 100ms or until there is an answer
2376 }
2377
2378
2379 int index = indexOfNotificationLocked(n.getKey());
2380 if (index < 0) {
2381 mNotificationList.add(r);
2382 mUsageStats.registerPostedByApp(r);
2383 } else {
2384 old = mNotificationList.get(index);
2385 mNotificationList.set(index, r);
2386 mUsageStats.registerUpdatedByApp(r, old);
2387 // Make sure we don't lose the foreground service state.
2388 notification.flags |=
2389 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2390 r.isUpdate = true;
2391 }
2392
2393 mNotificationsByKey.put(n.getKey(), r);
2394
2395 // Ensure if this is a foreground service that the proper additional
2396 // flags are set.
2397 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2398 notification.flags |= Notification.FLAG_ONGOING_EVENT
2399 | Notification.FLAG_NO_CLEAR;
2400 }
2401
2402 applyZenModeLocked(r);
2403 mRankingHelper.sort(mNotificationList);
2404
2405 if (notification.getSmallIcon() != null) {
2406 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2407 mListeners.notifyPostedLocked(n, oldSbn);
2408 } else {
2409 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2410 if (old != null && !old.isCanceled) {
2411 mListeners.notifyRemovedLocked(n);
2412 }
2413 // ATTENTION: in a future release we will bail out here
2414 // so that we do not play sounds, show lights, etc. for invalid
2415 // notifications
2416 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2417 + n.getPackageName());
2418 }
2419
2420 buzzBeepBlinkLocked(r);
2421 }
2422 }
2423 }
2424
Christoph Studer265c1052014-07-23 17:14:33 +02002425 /**
2426 * Ensures that grouped notification receive their special treatment.
2427 *
2428 * <p>Cancels group children if the new notification causes a group to lose
2429 * its summary.</p>
2430 *
2431 * <p>Updates mSummaryByGroupKey.</p>
2432 */
2433 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2434 int callingUid, int callingPid) {
2435 StatusBarNotification sbn = r.sbn;
2436 Notification n = sbn.getNotification();
2437 String group = sbn.getGroupKey();
2438 boolean isSummary = n.isGroupSummary();
2439
2440 Notification oldN = old != null ? old.sbn.getNotification() : null;
2441 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2442 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2443
2444 if (oldIsSummary) {
2445 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2446 if (removedSummary != old) {
2447 String removedKey =
2448 removedSummary != null ? removedSummary.getKey() : "<null>";
2449 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2450 ", removed=" + removedKey);
2451 }
2452 }
2453 if (isSummary) {
2454 mSummaryByGroupKey.put(group, r);
2455 }
2456
2457 // Clear out group children of the old notification if the update
2458 // causes the group summary to go away. This happens when the old
2459 // notification was a summary and the new one isn't, or when the old
2460 // notification was a summary and its group key changed.
2461 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2462 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
2463 REASON_GROUP_SUMMARY_CANCELED);
2464 }
2465 }
2466
2467 /**
2468 * Performs group notification optimizations if SysUI is the only active
2469 * notification listener and returns whether the given notification should
2470 * be ignored.
2471 *
2472 * <p>Returns true if the given notification is a child of a group with a
2473 * summary, which means that SysUI will never show it, and hence the new
Christoph Studer4a9849b2015-01-06 18:55:08 +01002474 * notification can be safely ignored. Also cancels any previous instance
2475 * of the ignored notification.</p>
Christoph Studer265c1052014-07-23 17:14:33 +02002476 *
2477 * <p>For summaries, cancels all children of that group, as SysUI will
2478 * never show them anymore.</p>
2479 *
2480 * @return true if the given notification can be ignored as an optimization
2481 */
2482 private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r,
Christoph Studer4a9849b2015-01-06 18:55:08 +01002483 NotificationRecord old, int callingUid, int callingPid) {
Selim Cinekb5605e52015-02-20 18:21:41 +01002484 if (!ENABLE_CHILD_NOTIFICATIONS) {
2485 // No optimizations are possible if listeners want groups.
2486 if (mListeners.notificationGroupsDesired()) {
2487 return false;
Christoph Studer265c1052014-07-23 17:14:33 +02002488 }
Selim Cinekb5605e52015-02-20 18:21:41 +01002489
2490 StatusBarNotification sbn = r.sbn;
2491 String group = sbn.getGroupKey();
2492 boolean isSummary = sbn.getNotification().isGroupSummary();
2493 boolean isChild = sbn.getNotification().isGroupChild();
2494
2495 NotificationRecord summary = mSummaryByGroupKey.get(group);
2496 if (isChild && summary != null) {
2497 // Child with an active summary -> ignore
Christoph Studer4a9849b2015-01-06 18:55:08 +01002498 if (DBG) {
Selim Cinekb5605e52015-02-20 18:21:41 +01002499 Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary "
2500 + summary.getKey());
Christoph Studer4a9849b2015-01-06 18:55:08 +01002501 }
Selim Cinekb5605e52015-02-20 18:21:41 +01002502 // Make sure we don't leave an old version of the notification around.
2503 if (old != null) {
2504 if (DBG) {
2505 Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey());
2506 }
2507 cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION);
2508 }
2509 return true;
2510 } else if (isSummary) {
2511 // Summary -> cancel children
2512 cancelGroupChildrenLocked(r, callingUid, callingPid, null,
2513 REASON_GROUP_OPTIMIZATION);
Christoph Studer4a9849b2015-01-06 18:55:08 +01002514 }
Christoph Studer265c1052014-07-23 17:14:33 +02002515 }
2516 return false;
2517 }
2518
Chris Wrena3446562014-06-03 18:11:47 -04002519 private void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04002520 boolean buzz = false;
2521 boolean beep = false;
2522 boolean blink = false;
2523
Chris Wrena3446562014-06-03 18:11:47 -04002524 final Notification notification = record.sbn.getNotification();
2525
2526 // Should this notification make noise, vibe, or use the LED?
Chris Wrenbdf33762015-12-04 15:50:51 -05002527 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_HIGH;
Chris Wrence00a232014-11-21 16:25:19 -05002528 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
Chris Wrena3446562014-06-03 18:11:47 -04002529 if (DBG || record.isIntercepted())
2530 Slog.v(TAG,
2531 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2532 " intercept=" + record.isIntercepted()
2533 );
2534
2535 final int currentUser;
2536 final long token = Binder.clearCallingIdentity();
2537 try {
2538 currentUser = ActivityManager.getCurrentUser();
2539 } finally {
2540 Binder.restoreCallingIdentity(token);
2541 }
2542
2543 // If we're not supposed to beep, vibrate, etc. then don't.
John Spurlock32fe4c62014-10-02 12:16:02 -04002544 final String disableEffects = disableNotificationEffects(record);
2545 if (disableEffects != null) {
2546 ZenLog.traceDisableEffects(record, disableEffects);
2547 }
2548 if (disableEffects == null
Chris Wrena3446562014-06-03 18:11:47 -04002549 && (!(record.isUpdate
2550 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
2551 && (record.getUserId() == UserHandle.USER_ALL ||
2552 record.getUserId() == currentUser ||
2553 mUserProfiles.isCurrentProfile(record.getUserId()))
2554 && canInterrupt
2555 && mSystemReady
2556 && mAudioManager != null) {
2557 if (DBG) Slog.v(TAG, "Interrupting!");
2558
2559 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2560
2561 // sound
2562
2563 // should we use the default notification sound? (indicated either by
2564 // DEFAULT_SOUND or because notification.sound is pointing at
2565 // Settings.System.NOTIFICATION_SOUND)
2566 final boolean useDefaultSound =
2567 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2568 Settings.System.DEFAULT_NOTIFICATION_URI
2569 .equals(notification.sound);
2570
2571 Uri soundUri = null;
2572 boolean hasValidSound = false;
2573
2574 if (useDefaultSound) {
2575 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2576
2577 // check to see if the default notification sound is silent
2578 ContentResolver resolver = getContext().getContentResolver();
2579 hasValidSound = Settings.System.getString(resolver,
2580 Settings.System.NOTIFICATION_SOUND) != null;
2581 } else if (notification.sound != null) {
2582 soundUri = notification.sound;
2583 hasValidSound = (soundUri != null);
2584 }
2585
2586 if (hasValidSound) {
2587 boolean looping =
2588 (notification.flags & Notification.FLAG_INSISTENT) != 0;
Marco Nelissen1c066302014-11-18 10:48:12 -08002589 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
Chris Wren6054e612014-11-25 17:16:46 -05002590 mSoundNotificationKey = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04002591 // do not play notifications if stream volume is 0 (typically because
2592 // ringer mode is silent) or if there is a user of exclusive audio focus
Jean-Michel Trivi81f871e2014-08-06 16:32:38 -07002593 if ((mAudioManager.getStreamVolume(
2594 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2595 && !mAudioManager.isAudioFocusExclusive()) {
Chris Wrena3446562014-06-03 18:11:47 -04002596 final long identity = Binder.clearCallingIdentity();
2597 try {
2598 final IRingtonePlayer player =
2599 mAudioManager.getRingtonePlayer();
2600 if (player != null) {
2601 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
Jean-Michel Trivi81f871e2014-08-06 16:32:38 -07002602 + " with attributes " + audioAttributes);
Chris Wrena3446562014-06-03 18:11:47 -04002603 player.playAsync(soundUri, record.sbn.getUser(), looping,
Jean-Michel Trivi81f871e2014-08-06 16:32:38 -07002604 audioAttributes);
Chris Wren82ba59d2015-06-05 11:23:44 -04002605 beep = true;
Chris Wrena3446562014-06-03 18:11:47 -04002606 }
2607 } catch (RemoteException e) {
2608 } finally {
2609 Binder.restoreCallingIdentity(identity);
2610 }
2611 }
2612 }
2613
2614 // vibrate
2615 // Does the notification want to specify its own vibration?
2616 final boolean hasCustomVibrate = notification.vibrate != null;
2617
2618 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2619 // mode, and no other vibration is specified, we fall back to vibration
2620 final boolean convertSoundToVibration =
2621 !hasCustomVibrate
2622 && hasValidSound
John Spurlock661f2cf2014-11-17 10:29:10 -05002623 && (mAudioManager.getRingerModeInternal()
Chris Wrena3446562014-06-03 18:11:47 -04002624 == AudioManager.RINGER_MODE_VIBRATE);
2625
2626 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2627 final boolean useDefaultVibrate =
2628 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2629
2630 if ((useDefaultVibrate || convertSoundToVibration || hasCustomVibrate)
John Spurlock661f2cf2014-11-17 10:29:10 -05002631 && !(mAudioManager.getRingerModeInternal()
Chris Wrena3446562014-06-03 18:11:47 -04002632 == AudioManager.RINGER_MODE_SILENT)) {
Chris Wren6054e612014-11-25 17:16:46 -05002633 mVibrateNotificationKey = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04002634
2635 if (useDefaultVibrate || convertSoundToVibration) {
2636 // Escalate privileges so we can use the vibrator even if the
2637 // notifying app does not have the VIBRATE permission.
2638 long identity = Binder.clearCallingIdentity();
2639 try {
2640 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2641 useDefaultVibrate ? mDefaultVibrationPattern
2642 : mFallbackVibrationPattern,
2643 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
John Spurlock7b414672014-07-18 13:02:39 -04002644 ? 0: -1, audioAttributesForNotification(notification));
Chris Wren82ba59d2015-06-05 11:23:44 -04002645 buzz = true;
Chris Wrena3446562014-06-03 18:11:47 -04002646 } finally {
2647 Binder.restoreCallingIdentity(identity);
2648 }
2649 } else if (notification.vibrate.length > 1) {
2650 // If you want your own vibration pattern, you need the VIBRATE
2651 // permission
2652 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2653 notification.vibrate,
2654 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
John Spurlock7b414672014-07-18 13:02:39 -04002655 ? 0: -1, audioAttributesForNotification(notification));
Chris Wren82ba59d2015-06-05 11:23:44 -04002656 buzz = true;
Chris Wrena3446562014-06-03 18:11:47 -04002657 }
2658 }
2659 }
2660
2661 // light
2662 // release the light
2663 boolean wasShowLights = mLights.remove(record.getKey());
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002664 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2665 && ((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05002666 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Chris Wrena3446562014-06-03 18:11:47 -04002667 mLights.add(record.getKey());
2668 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04002669 if (mUseAttentionLight) {
2670 mAttentionLight.pulse();
2671 }
Chris Wren82ba59d2015-06-05 11:23:44 -04002672 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04002673 } else if (wasShowLights) {
2674 updateLightsLocked();
2675 }
Chris Wren82ba59d2015-06-05 11:23:44 -04002676 if (buzz || beep || blink) {
Julia Reynolds61721582016-01-05 08:35:25 -05002677 if (((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05002678 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
Julia Reynolds61721582016-01-05 08:35:25 -05002679 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2680 } else {
2681 EventLogTags.writeNotificationAlert(record.getKey(),
2682 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2683 mHandler.post(mBuzzBeepBlinked);
2684 }
John Spurlockcad57682014-07-26 17:09:56 -04002685 }
Chris Wrena3446562014-06-03 18:11:47 -04002686 }
2687
John Spurlock7b414672014-07-18 13:02:39 -04002688 private static AudioAttributes audioAttributesForNotification(Notification n) {
Marco Nelissen1c066302014-11-18 10:48:12 -08002689 if (n.audioAttributes != null
2690 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2691 // the audio attributes are set and different from the default, use them
John Spurlockbfa5dc42014-07-28 23:30:45 -04002692 return n.audioAttributes;
Jean-Michel Triviceb79bc2014-09-05 11:09:14 -07002693 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2694 // the stream type is valid, use it
2695 return new AudioAttributes.Builder()
2696 .setInternalLegacyStreamType(n.audioStreamType)
2697 .build();
2698 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2699 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2700 } else {
2701 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2702 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
John Spurlockbfa5dc42014-07-28 23:30:45 -04002703 }
John Spurlock7b414672014-07-18 13:02:39 -04002704 }
2705
Adam Lesinski182f73f2013-12-05 16:48:06 -08002706 void showNextToastLocked() {
2707 ToastRecord record = mToastQueue.get(0);
2708 while (record != null) {
2709 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2710 try {
2711 record.callback.show();
2712 scheduleTimeoutLocked(record);
2713 return;
2714 } catch (RemoteException e) {
2715 Slog.w(TAG, "Object died trying to show notification " + record.callback
2716 + " in package " + record.pkg);
2717 // remove it from the list and let the process die
2718 int index = mToastQueue.indexOf(record);
2719 if (index >= 0) {
2720 mToastQueue.remove(index);
2721 }
2722 keepProcessAliveLocked(record.pid);
2723 if (mToastQueue.size() > 0) {
2724 record = mToastQueue.get(0);
2725 } else {
2726 record = null;
2727 }
2728 }
2729 }
2730 }
2731
2732 void cancelToastLocked(int index) {
2733 ToastRecord record = mToastQueue.get(index);
2734 try {
2735 record.callback.hide();
2736 } catch (RemoteException e) {
2737 Slog.w(TAG, "Object died trying to hide notification " + record.callback
2738 + " in package " + record.pkg);
2739 // don't worry about this, we're about to remove it from
2740 // the list anyway
2741 }
2742 mToastQueue.remove(index);
2743 keepProcessAliveLocked(record.pid);
2744 if (mToastQueue.size() > 0) {
2745 // Show the next one. If the callback fails, this will remove
2746 // it from the list, so don't assume that the list hasn't changed
2747 // after this point.
2748 showNextToastLocked();
2749 }
2750 }
2751
2752 private void scheduleTimeoutLocked(ToastRecord r)
2753 {
2754 mHandler.removeCallbacksAndMessages(r);
2755 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
2756 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
2757 mHandler.sendMessageDelayed(m, delay);
2758 }
2759
2760 private void handleTimeout(ToastRecord record)
2761 {
2762 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
2763 synchronized (mToastQueue) {
2764 int index = indexOfToastLocked(record.pkg, record.callback);
2765 if (index >= 0) {
2766 cancelToastLocked(index);
2767 }
2768 }
2769 }
2770
2771 // lock on mToastQueue
2772 int indexOfToastLocked(String pkg, ITransientNotification callback)
2773 {
2774 IBinder cbak = callback.asBinder();
2775 ArrayList<ToastRecord> list = mToastQueue;
2776 int len = list.size();
2777 for (int i=0; i<len; i++) {
2778 ToastRecord r = list.get(i);
2779 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
2780 return i;
2781 }
2782 }
2783 return -1;
2784 }
2785
2786 // lock on mToastQueue
2787 void keepProcessAliveLocked(int pid)
2788 {
2789 int toastCount = 0; // toasts from this pid
2790 ArrayList<ToastRecord> list = mToastQueue;
2791 int N = list.size();
2792 for (int i=0; i<N; i++) {
2793 ToastRecord r = list.get(i);
2794 if (r.pid == pid) {
2795 toastCount++;
2796 }
2797 }
2798 try {
2799 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
2800 } catch (RemoteException e) {
2801 // Shouldn't happen.
2802 }
2803 }
2804
Chris Wrenf9536642014-04-17 10:01:54 -04002805 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04002806 if (!(message.obj instanceof RankingReconsideration)) return;
2807 RankingReconsideration recon = (RankingReconsideration) message.obj;
2808 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04002809 boolean changed;
Chris Wren470c1ac2014-05-21 15:28:10 -04002810 synchronized (mNotificationList) {
2811 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
2812 if (record == null) {
2813 return;
Chris Wrenf9536642014-04-17 10:01:54 -04002814 }
Chris Wren333a61c2014-05-28 16:40:57 -04002815 int indexBefore = findNotificationRecordIndexLocked(record);
2816 boolean interceptBefore = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04002817 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04002818 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04002819 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04002820 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04002821 int indexAfter = findNotificationRecordIndexLocked(record);
2822 boolean interceptAfter = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04002823 int visibilityAfter = record.getPackageVisibilityOverride();
2824 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
2825 || visibilityBefore != visibilityAfter;
Chris Wrena3446562014-06-03 18:11:47 -04002826 if (interceptBefore && !interceptAfter) {
2827 buzzBeepBlinkLocked(record);
2828 }
Chris Wrenf9536642014-04-17 10:01:54 -04002829 }
Chris Wren333a61c2014-05-28 16:40:57 -04002830 if (changed) {
Chris Wren470c1ac2014-05-21 15:28:10 -04002831 scheduleSendRankingUpdate();
2832 }
2833 }
2834
Chris Wren51017d02015-12-15 15:34:46 -05002835 private void handleRankingSort() {
Chris Wren54bbef42014-07-09 18:37:56 -04002836 synchronized (mNotificationList) {
2837 final int N = mNotificationList.size();
2838 ArrayList<String> orderBefore = new ArrayList<String>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04002839 int[] visibilities = new int[N];
Julia Reynolds69766692016-02-01 15:35:08 -05002840 int [] importances = new int[N];
Chris Wren54bbef42014-07-09 18:37:56 -04002841 for (int i = 0; i < N; i++) {
2842 final NotificationRecord r = mNotificationList.get(i);
2843 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04002844 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds69766692016-02-01 15:35:08 -05002845 importances[i] = r.getImportance();
Chris Wren54bbef42014-07-09 18:37:56 -04002846 mRankingHelper.extractSignals(r);
2847 }
Chris Wren19a02b02015-12-22 10:34:22 -05002848 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04002849 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04002850 final NotificationRecord r = mNotificationList.get(i);
2851 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05002852 || visibilities[i] != r.getPackageVisibilityOverride()
2853 || importances[i] != r.getImportance()) {
Chris Wren54bbef42014-07-09 18:37:56 -04002854 scheduleSendRankingUpdate();
2855 return;
2856 }
2857 }
2858 }
2859 }
2860
Christoph Studerd5092bc2014-07-03 17:47:58 +02002861 // let zen mode evaluate this record
Chris Wren333a61c2014-05-28 16:40:57 -04002862 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02002863 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002864 if (record.isIntercepted()) {
Julia Reynoldsd5607292016-02-05 15:25:58 -05002865 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
2866 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
2867 | (mZenModeHelper.shouldSuppressWhenScreenOn()
2868 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002869 record.setSuppressedVisualEffects(suppressed);
2870 }
Chris Wren333a61c2014-05-28 16:40:57 -04002871 }
2872
Chris Wren470c1ac2014-05-21 15:28:10 -04002873 // lock on mNotificationList
2874 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04002875 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04002876 }
2877
2878 private void scheduleSendRankingUpdate() {
2879 mHandler.removeMessages(MESSAGE_SEND_RANKING_UPDATE);
2880 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
2881 mHandler.sendMessage(m);
2882 }
2883
2884 private void handleSendRankingUpdate() {
2885 synchronized (mNotificationList) {
Chris Wren333a61c2014-05-28 16:40:57 -04002886 mListeners.notifyRankingUpdateLocked();
Chris Wrenf9536642014-04-17 10:01:54 -04002887 }
2888 }
2889
John Spurlockd8afe3c2014-08-01 14:04:07 -04002890 private void scheduleListenerHintsChanged(int state) {
2891 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
2892 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04002893 }
2894
Christoph Studer85a384b2014-08-27 20:16:15 +02002895 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
2896 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
2897 mHandler.obtainMessage(
2898 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
2899 listenerInterruptionFilter,
2900 0).sendToTarget();
2901 }
2902
John Spurlockd8afe3c2014-08-01 14:04:07 -04002903 private void handleListenerHintsChanged(int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04002904 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002905 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04002906 }
2907 }
2908
Christoph Studer85a384b2014-08-27 20:16:15 +02002909 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
2910 synchronized (mNotificationList) {
2911 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
2912 }
2913 }
2914
Adam Lesinski182f73f2013-12-05 16:48:06 -08002915 private final class WorkerHandler extends Handler
2916 {
2917 @Override
2918 public void handleMessage(Message msg)
2919 {
2920 switch (msg.what)
2921 {
2922 case MESSAGE_TIMEOUT:
2923 handleTimeout((ToastRecord)msg.obj);
2924 break;
John Spurlock056c5192014-04-20 21:52:01 -04002925 case MESSAGE_SAVE_POLICY_FILE:
2926 handleSavePolicyFile();
2927 break;
Chris Wrenf9536642014-04-17 10:01:54 -04002928 case MESSAGE_SEND_RANKING_UPDATE:
2929 handleSendRankingUpdate();
2930 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002931 case MESSAGE_LISTENER_HINTS_CHANGED:
2932 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04002933 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02002934 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
2935 handleListenerInterruptionFilterChanged(msg.arg1);
2936 break;
Chris Wrenf9536642014-04-17 10:01:54 -04002937 }
2938 }
2939
2940 }
2941
Chris Wren51017d02015-12-15 15:34:46 -05002942 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04002943 {
Chris Wren51017d02015-12-15 15:34:46 -05002944 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04002945 super(looper);
2946 }
2947
2948 @Override
2949 public void handleMessage(Message msg) {
2950 switch (msg.what) {
2951 case MESSAGE_RECONSIDER_RANKING:
2952 handleRankingReconsideration(msg);
2953 break;
Chris Wren51017d02015-12-15 15:34:46 -05002954 case MESSAGE_RANKING_SORT:
2955 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04002956 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002957 }
2958 }
Chris Wren51017d02015-12-15 15:34:46 -05002959
2960 public void requestSort() {
2961 removeMessages(MESSAGE_RANKING_SORT);
2962 sendEmptyMessage(MESSAGE_RANKING_SORT);
2963 }
2964
2965 public void requestReconsideration(RankingReconsideration recon) {
2966 Message m = Message.obtain(this,
2967 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
2968 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
2969 sendMessageDelayed(m, delay);
2970 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002971 }
2972
Adam Lesinski182f73f2013-12-05 16:48:06 -08002973 // Notifications
2974 // ============================================================================
2975 static int clamp(int x, int low, int high) {
2976 return (x < low) ? low : ((x > high) ? high : x);
2977 }
2978
2979 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
2980 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
svetoslavganov75986cf2009-05-14 22:28:01 -07002981 if (!manager.isEnabled()) {
2982 return;
2983 }
2984
2985 AccessibilityEvent event =
2986 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
2987 event.setPackageName(packageName);
2988 event.setClassName(Notification.class.getName());
2989 event.setParcelableData(notification);
2990 CharSequence tickerText = notification.tickerText;
2991 if (!TextUtils.isEmpty(tickerText)) {
2992 event.getText().add(tickerText);
2993 }
2994
2995 manager.sendAccessibilityEvent(event);
2996 }
2997
Christoph Studer546bec82014-03-14 12:17:12 +01002998 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
Joe Onorato46439ce2010-11-19 13:56:21 -08002999 // tell the app
3000 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003001 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08003002 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003003 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08003004 } catch (PendingIntent.CanceledException ex) {
3005 // do nothing - there's no relevant way to recover, and
3006 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04003007 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08003008 }
3009 }
3010 }
3011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003012 // status bar
Dan Sandlerd63f9322015-05-06 15:18:49 -04003013 if (r.getNotification().getSmallIcon() != null) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02003014 r.isCanceled = true;
Chris Wren333a61c2014-05-28 16:40:57 -04003015 mListeners.notifyRemovedLocked(r.sbn);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003016 }
3017
Chris Wren6054e612014-11-25 17:16:46 -05003018 final String canceledKey = r.getKey();
3019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 // sound
Chris Wren6054e612014-11-25 17:16:46 -05003021 if (canceledKey.equals(mSoundNotificationKey)) {
3022 mSoundNotificationKey = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -07003023 final long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003025 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07003026 if (player != null) {
3027 player.stopAsync();
3028 }
3029 } catch (RemoteException e) {
3030 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003031 Binder.restoreCallingIdentity(identity);
3032 }
3033 }
3034
3035 // vibrate
Chris Wren6054e612014-11-25 17:16:46 -05003036 if (canceledKey.equals(mVibrateNotificationKey)) {
3037 mVibrateNotificationKey = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003038 long identity = Binder.clearCallingIdentity();
3039 try {
3040 mVibrator.cancel();
3041 }
3042 finally {
3043 Binder.restoreCallingIdentity(identity);
3044 }
3045 }
3046
3047 // light
Chris Wren6054e612014-11-25 17:16:46 -05003048 mLights.remove(canceledKey);
Daniel Sandler23d7c702013-03-07 16:32:06 -05003049
Christoph Studer546bec82014-03-14 12:17:12 +01003050 // Record usage stats
3051 switch (reason) {
3052 case REASON_DELEGATE_CANCEL:
3053 case REASON_DELEGATE_CANCEL_ALL:
3054 case REASON_LISTENER_CANCEL:
3055 case REASON_LISTENER_CANCEL_ALL:
3056 mUsageStats.registerDismissedByUser(r);
3057 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05003058 case REASON_APP_CANCEL:
3059 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01003060 mUsageStats.registerRemovedByApp(r);
3061 break;
Christoph Studer546bec82014-03-14 12:17:12 +01003062 }
3063
Christoph Studercef37cf2014-07-25 14:18:17 +02003064 mNotificationsByKey.remove(r.sbn.getKey());
Christoph Studer265c1052014-07-23 17:14:33 +02003065 String groupKey = r.getGroupKey();
3066 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3067 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3068 mSummaryByGroupKey.remove(groupKey);
3069 }
Christoph Studercef37cf2014-07-25 14:18:17 +02003070
Daniel Sandler23d7c702013-03-07 16:32:06 -05003071 // Save it for users of getHistoricalNotifications()
3072 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02003073
Chris Wren6650e572015-05-15 17:19:25 -04003074 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -04003075 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3076 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003077 }
3078
3079 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07003080 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003081 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003082 */
John Spurlocke6a7d932014-03-13 12:29:00 -04003083 void cancelNotification(final int callingUid, final int callingPid,
3084 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003085 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04003086 final int userId, final int reason, final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003087 // In enqueueNotificationInternal notifications are added by scheduling the
3088 // work on the worker handler. Hence, we also schedule the cancel on this
3089 // handler to avoid a scenario where an add notification call followed by a
3090 // remove notification call ends up in not removing the notification.
3091 mHandler.post(new Runnable() {
3092 @Override
3093 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003094 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08003095 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3096 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003098 synchronized (mNotificationList) {
3099 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3100 if (index >= 0) {
3101 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003102
Christoph Studer546bec82014-03-14 12:17:12 +01003103 // Ideally we'd do this in the caller of this method. However, that would
3104 // require the caller to also find the notification.
3105 if (reason == REASON_DELEGATE_CLICK) {
3106 mUsageStats.registerClickedByUser(r);
3107 }
3108
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003109 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3110 return;
3111 }
3112 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3113 return;
3114 }
3115
3116 mNotificationList.remove(index);
3117
Christoph Studer546bec82014-03-14 12:17:12 +01003118 cancelNotificationLocked(r, sendDelete, reason);
Christoph Studer265c1052014-07-23 17:14:33 +02003119 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
3120 REASON_GROUP_SUMMARY_CANCELED);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003121 updateLightsLocked();
3122 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003124 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003125 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 }
3127
3128 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07003129 * Determine whether the userId applies to the notification in question, either because
3130 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3131 */
3132 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3133 return
3134 // looking for USER_ALL notifications? match everything
3135 userId == UserHandle.USER_ALL
3136 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003137 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07003138 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003139 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07003140 }
3141
3142 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003143 * Determine whether the userId applies to the notification in question, either because
3144 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01003145 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003146 */
Kenny Guy2a764942014-04-02 13:29:20 +01003147 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00003148 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04003149 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003150 }
3151
3152 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05003153 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 * {@code mustHaveFlags}.
3155 */
John Spurlocke6a7d932014-03-13 12:29:00 -04003156 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
Julia Reynoldsef37f282016-02-12 09:11:27 -05003157 int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04003158 ManagedServiceInfo listener) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003159 String listenerName = listener == null ? null : listener.component.toShortString();
John Spurlocke6a7d932014-03-13 12:29:00 -04003160 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3161 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
Christoph Studere4ef156b2014-07-04 18:41:57 +02003162 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163
3164 synchronized (mNotificationList) {
3165 final int N = mNotificationList.size();
Christoph Studere4ef156b2014-07-04 18:41:57 +02003166 ArrayList<NotificationRecord> canceledNotifications = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 for (int i = N-1; i >= 0; --i) {
3168 NotificationRecord r = mNotificationList.get(i);
Daniel Sandler321e9c52012-10-12 10:59:26 -07003169 if (!notificationMatchesUserId(r, userId)) {
Dianne Hackborn41203752012-08-31 14:05:51 -07003170 continue;
3171 }
Amith Yamasani5ec00e92012-11-07 16:58:30 -08003172 // Don't remove notifications to all, if there's no package name specified
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003173 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
Amith Yamasani5ec00e92012-11-07 16:58:30 -08003174 continue;
3175 }
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003176 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 continue;
3178 }
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003179 if ((r.getFlags() & mustNotHaveFlags) != 0) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07003180 continue;
3181 }
Daniel Sandler4f91efd2013-04-25 16:38:41 -04003182 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 continue;
3184 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003185 if (canceledNotifications == null) {
3186 canceledNotifications = new ArrayList<>();
3187 }
3188 canceledNotifications.add(r);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08003189 if (!doit) {
3190 return true;
3191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003192 mNotificationList.remove(i);
Christoph Studer546bec82014-03-14 12:17:12 +01003193 cancelNotificationLocked(r, false, reason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003194 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003195 if (doit && canceledNotifications != null) {
3196 final int M = canceledNotifications.size();
3197 for (int i = 0; i < M; i++) {
3198 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Christoph Studer265c1052014-07-23 17:14:33 +02003199 listenerName, REASON_GROUP_SUMMARY_CANCELED);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003200 }
3201 }
3202 if (canceledNotifications != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003203 updateLightsLocked();
3204 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003205 return canceledNotifications != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206 }
3207 }
3208
Adam Lesinski350159c2014-03-27 11:15:11 -07003209 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04003210 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003211 String listenerName = listener == null ? null : listener.component.toShortString();
John Spurlocke6a7d932014-03-13 12:29:00 -04003212 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
Christoph Studere4ef156b2014-07-04 18:41:57 +02003213 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01003214
Christoph Studere4ef156b2014-07-04 18:41:57 +02003215 ArrayList<NotificationRecord> canceledNotifications = null;
Adam Lesinskie8240262014-03-26 16:01:00 -07003216 final int N = mNotificationList.size();
3217 for (int i=N-1; i>=0; i--) {
3218 NotificationRecord r = mNotificationList.get(i);
Kenny Guya263e4e2014-03-03 18:24:03 +00003219 if (includeCurrentProfiles) {
3220 if (!notificationMatchesCurrentProfiles(r, userId)) {
3221 continue;
3222 }
3223 } else {
3224 if (!notificationMatchesUserId(r, userId)) {
3225 continue;
3226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003227 }
3228
Adam Lesinskie8240262014-03-26 16:01:00 -07003229 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3230 | Notification.FLAG_NO_CLEAR)) == 0) {
3231 mNotificationList.remove(i);
Christoph Studer546bec82014-03-14 12:17:12 +01003232 cancelNotificationLocked(r, true, reason);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003233 // Make a note so we can cancel children later.
3234 if (canceledNotifications == null) {
3235 canceledNotifications = new ArrayList<>();
3236 }
3237 canceledNotifications.add(r);
Adam Lesinskie8240262014-03-26 16:01:00 -07003238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003240 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3241 for (int i = 0; i < M; i++) {
3242 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Christoph Studer265c1052014-07-23 17:14:33 +02003243 listenerName, REASON_GROUP_SUMMARY_CANCELED);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003244 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003245 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 }
3247
Christoph Studere4ef156b2014-07-04 18:41:57 +02003248 // Warning: The caller is responsible for invoking updateLightsLocked().
3249 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Christoph Studer265c1052014-07-23 17:14:33 +02003250 String listenerName, int reason) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003251 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02003252 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003253 return;
3254 }
3255
3256 String pkg = r.sbn.getPackageName();
3257 int userId = r.getUserId();
3258
3259 if (pkg == null) {
3260 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3261 return;
3262 }
3263
3264 final int N = mNotificationList.size();
3265 for (int i = N - 1; i >= 0; i--) {
3266 NotificationRecord childR = mNotificationList.get(i);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003267 StatusBarNotification childSbn = childR.sbn;
Christoph Studerc44caa92014-08-22 19:16:00 +02003268 if (childR.getNotification().isGroupChild() &&
3269 childR.getGroupKey().equals(r.getGroupKey())) {
Christoph Studer265c1052014-07-23 17:14:33 +02003270 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3271 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003272 mNotificationList.remove(i);
Christoph Studer265c1052014-07-23 17:14:33 +02003273 cancelNotificationLocked(childR, false, reason);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003274 }
3275 }
3276 }
3277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003278 // lock on mNotificationList
Adam Lesinski182f73f2013-12-05 16:48:06 -08003279 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003280 {
The Android Open Source Project10592532009-03-18 17:39:46 -07003281 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05003282 NotificationRecord ledNotification = null;
3283 while (ledNotification == null && !mLights.isEmpty()) {
3284 final String owner = mLights.get(mLights.size() - 1);
3285 ledNotification = mNotificationsByKey.get(owner);
3286 if (ledNotification == null) {
3287 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3288 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003289 }
3290 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05003291
Mike Lockwood63b5ad92011-08-30 09:55:30 -04003292 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05003293 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05003294 mNotificationLight.turnOff();
John Spurlockcb566aa2014-08-03 22:58:28 -04003295 mStatusBar.notificationLightOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07003296 } else {
Chris Wren6054e612014-11-25 17:16:46 -05003297 final Notification ledno = ledNotification.sbn.getNotification();
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003298 int ledARGB = ledno.ledARGB;
3299 int ledOnMS = ledno.ledOnMS;
3300 int ledOffMS = ledno.ledOffMS;
3301 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
Mike Lockwood670f9322010-01-20 12:13:36 -05003302 ledARGB = mDefaultNotificationColor;
3303 ledOnMS = mDefaultNotificationLedOn;
3304 ledOffMS = mDefaultNotificationLedOff;
3305 }
3306 if (mNotificationPulseEnabled) {
3307 // pulse repeatedly
Adam Lesinski182f73f2013-12-05 16:48:06 -08003308 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
Mike Lockwood670f9322010-01-20 12:13:36 -05003309 ledOnMS, ledOffMS);
Mike Lockwood670f9322010-01-20 12:13:36 -05003310 }
John Spurlock39292322014-08-13 11:00:59 -04003311 // let SystemUI make an independent decision
3312 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
The Android Open Source Project10592532009-03-18 17:39:46 -07003313 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003314 }
3315
3316 // lock on mNotificationList
Adam Lesinski182f73f2013-12-05 16:48:06 -08003317 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003318 {
3319 ArrayList<NotificationRecord> list = mNotificationList;
3320 final int len = list.size();
3321 for (int i=0; i<len; i++) {
3322 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01003323 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3324 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 return i;
3326 }
3327 }
3328 return -1;
3329 }
3330
Christoph Studer71f18fd2014-05-20 17:02:04 +02003331 // lock on mNotificationList
3332 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02003333 final int N = mNotificationList.size();
3334 for (int i = 0; i < N; i++) {
3335 if (key.equals(mNotificationList.get(i).getKey())) {
3336 return i;
3337 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02003338 }
Christoph Studerc5115552014-06-12 20:22:31 +02003339 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02003340 }
3341
Mike Lockwoodc22404a2009-12-02 11:15:02 -05003342 private void updateNotificationPulse() {
3343 synchronized (mNotificationList) {
3344 updateLightsLocked();
3345 }
3346 }
John Spurlocke677d712014-02-13 12:52:19 -05003347
John Spurlock7340fc82014-04-24 18:50:12 -04003348 private static boolean isUidSystem(int uid) {
3349 final int appid = UserHandle.getAppId(uid);
3350 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3351 }
John Spurlockb408e8e2014-04-23 21:12:45 -04003352
John Spurlock7340fc82014-04-24 18:50:12 -04003353 private static boolean isCallerSystem() {
3354 return isUidSystem(Binder.getCallingUid());
3355 }
3356
3357 private static void checkCallerIsSystem() {
3358 if (isCallerSystem()) {
3359 return;
3360 }
3361 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3362 }
3363
3364 private static void checkCallerIsSystemOrSameApp(String pkg) {
3365 if (isCallerSystem()) {
3366 return;
3367 }
3368 final int uid = Binder.getCallingUid();
3369 try {
3370 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3371 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04003372 if (ai == null) {
3373 throw new SecurityException("Unknown package " + pkg);
3374 }
John Spurlock7340fc82014-04-24 18:50:12 -04003375 if (!UserHandle.isSameApp(ai.uid, uid)) {
3376 throw new SecurityException("Calling uid " + uid + " gave package"
3377 + pkg + " which is owned by uid " + ai.uid);
3378 }
3379 } catch (RemoteException re) {
3380 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3381 }
3382 }
3383
John Spurlock32fe4c62014-10-02 12:16:02 -04003384 private static String callStateToString(int state) {
3385 switch (state) {
3386 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3387 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3388 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3389 default: return "CALL_STATE_UNKNOWN_" + state;
3390 }
3391 }
3392
3393 private void listenForCallState() {
3394 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3395 @Override
3396 public void onCallStateChanged(int state, String incomingNumber) {
3397 if (mCallState == state) return;
3398 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3399 mCallState = state;
3400 }
3401 }, PhoneStateListener.LISTEN_CALL_STATE);
3402 }
3403
Christoph Studer05ad4822014-05-16 14:16:03 +02003404 /**
3405 * Generates a NotificationRankingUpdate from 'sbns', considering only
3406 * notifications visible to the given listener.
Chris Wren333a61c2014-05-28 16:40:57 -04003407 *
3408 * <p>Caller must hold a lock on mNotificationList.</p>
Christoph Studer05ad4822014-05-16 14:16:03 +02003409 */
Chris Wren333a61c2014-05-28 16:40:57 -04003410 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04003411 final int N = mNotificationList.size();
3412 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02003413 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05003414 ArrayList<Integer> importance = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003415 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003416 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05003417 Bundle explanation = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04003418 for (int i = 0; i < N; i++) {
3419 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02003420 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02003421 continue;
3422 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003423 final String key = record.sbn.getKey();
3424 keys.add(key);
3425 importance.add(record.getImportance());
3426 if (record.getImportanceExplanation() != null) {
3427 explanation.putCharSequence(key, record.getImportanceExplanation());
3428 }
Chris Wren333a61c2014-05-28 16:40:57 -04003429 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05003430 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003431
Christoph Studer05ad4822014-05-16 14:16:03 +02003432 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003433 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003434 if (record.getPackageVisibilityOverride()
3435 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05003436 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003437 }
Christoph Studer05ad4822014-05-16 14:16:03 +02003438 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003439 final int M = keys.size();
3440 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02003441 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05003442 int[] importanceAr = new int[M];
3443 for (int i = 0; i < M; i++) {
3444 importanceAr[i] = importance.get(i);
3445 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003446 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds0421e6d2016-01-08 09:51:24 -05003447 suppressedVisualEffects, importanceAr, explanation);
Christoph Studer05ad4822014-05-16 14:16:03 +02003448 }
3449
Christoph Studercef37cf2014-07-25 14:18:17 +02003450 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3451 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3452 return false;
3453 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07003454 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02003455 return true;
3456 }
3457
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00003458 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003459 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003460 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00003461 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003462 } catch (RemoteException re) {
3463 throw new SecurityException("Could not talk to package manager service");
3464 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003465 }
3466
Chris Wren47633422016-01-22 09:56:59 -05003467 private class TrimCache {
3468 StatusBarNotification heavy;
3469 StatusBarNotification sbnClone;
3470 StatusBarNotification sbnCloneLight;
3471
3472 TrimCache(StatusBarNotification sbn) {
3473 heavy = sbn;
3474 }
3475
3476 StatusBarNotification ForListener(ManagedServiceInfo info) {
3477 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3478 if (sbnCloneLight == null) {
3479 sbnCloneLight = heavy.cloneLight();
3480 }
3481 return sbnCloneLight;
3482 } else {
3483 if (sbnClone == null) {
3484 sbnClone = heavy.clone();
3485 }
3486 return sbnClone;
3487 }
3488 }
3489 }
3490
Chris Wren51017d02015-12-15 15:34:46 -05003491 public class NotificationAssistant extends ManagedServices {
3492
3493 public NotificationAssistant() {
3494 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3495 }
3496
3497 @Override
3498 protected Config getConfig() {
3499 Config c = new Config();
3500 c.caption = "notification assistant";
3501 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
3502 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
3503 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
3504 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
3505 c.clientLabel = R.string.notification_assistant_binding_label;
3506 return c;
3507 }
3508
3509 @Override
3510 protected IInterface asInterface(IBinder binder) {
3511 return INotificationListener.Stub.asInterface(binder);
3512 }
3513
3514 @Override
3515 protected boolean checkType(IInterface service) {
3516 return service instanceof INotificationListener;
3517 }
3518
3519 @Override
3520 protected void onServiceAdded(ManagedServiceInfo info) {
3521 mListeners.registerGuestService(info);
3522 }
3523
3524 @Override
3525 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3526 mListeners.unregisterService(removed.service, removed.userid);
3527 }
Chris Wren47633422016-01-22 09:56:59 -05003528
3529 public void onNotificationEnqueued(final NotificationRecord r) {
3530 final StatusBarNotification sbn = r.sbn;
3531 TrimCache trimCache = new TrimCache(sbn);
3532
3533 // mServices is the list inside ManagedServices of all the assistants,
3534 // There should be only one, but it's a list, so while we enforce
3535 // singularity elsewhere, we keep it general here, to avoid surprises.
3536 for (final ManagedServiceInfo info : NotificationAssistant.this.mServices) {
3537 boolean sbnVisible = isVisibleToListener(sbn, info);
3538 if (!sbnVisible) {
3539 continue;
3540 }
3541
3542 final int importance = r.getImportance();
3543 final boolean fromUser = r.isImportanceFromUser();
3544 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
3545 mAssistantHandler.post(new Runnable() {
3546 @Override
3547 public void run() {
3548 notifyEnqueued(info, sbnToPost, importance, fromUser);
3549 }
3550 });
3551 }
3552 }
3553
3554 private void notifyEnqueued(final ManagedServiceInfo info,
3555 final StatusBarNotification sbn, int importance, boolean fromUser) {
3556 final INotificationListener assistant = (INotificationListener) info.service;
3557 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3558 try {
3559 assistant.onNotificationEnqueued(sbnHolder, importance, fromUser);
3560 } catch (RemoteException ex) {
3561 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
3562 }
3563 }
3564
3565 public boolean isEnabled() {
3566 return !mServices.isEmpty();
3567 }
Chris Wren51017d02015-12-15 15:34:46 -05003568 }
3569
John Spurlock7340fc82014-04-24 18:50:12 -04003570 public class NotificationListeners extends ManagedServices {
3571
Christoph Studerb82bc782014-08-20 14:29:43 +02003572 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
Christoph Studer265c1052014-07-23 17:14:33 +02003573 private boolean mNotificationGroupsDesired;
Christoph Studerb82bc782014-08-20 14:29:43 +02003574
John Spurlock7340fc82014-04-24 18:50:12 -04003575 public NotificationListeners() {
3576 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3577 }
3578
3579 @Override
3580 protected Config getConfig() {
3581 Config c = new Config();
3582 c.caption = "notification listener";
3583 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3584 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3585 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3586 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3587 c.clientLabel = R.string.notification_listener_binding_label;
3588 return c;
3589 }
3590
3591 @Override
3592 protected IInterface asInterface(IBinder binder) {
3593 return INotificationListener.Stub.asInterface(binder);
3594 }
3595
3596 @Override
Chris Wren51017d02015-12-15 15:34:46 -05003597 protected boolean checkType(IInterface service) {
3598 return service instanceof INotificationListener;
3599 }
3600
3601 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04003602 public void onServiceAdded(ManagedServiceInfo info) {
3603 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04003604 final NotificationRankingUpdate update;
Christoph Studer05ad4822014-05-16 14:16:03 +02003605 synchronized (mNotificationList) {
Christoph Studer265c1052014-07-23 17:14:33 +02003606 updateNotificationGroupsDesiredLocked();
Chris Wren333a61c2014-05-28 16:40:57 -04003607 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02003608 }
John Spurlock7340fc82014-04-24 18:50:12 -04003609 try {
Chris Wren333a61c2014-05-28 16:40:57 -04003610 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04003611 } catch (RemoteException e) {
3612 // we tried
3613 }
3614 }
3615
John Spurlock1fa865f2014-07-21 14:56:39 -04003616 @Override
3617 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003618 if (mListenersDisablingEffects.remove(removed)) {
3619 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01003620 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04003621 }
Christoph Studerb82bc782014-08-20 14:29:43 +02003622 mLightTrimListeners.remove(removed);
Christoph Studer265c1052014-07-23 17:14:33 +02003623 updateNotificationGroupsDesiredLocked();
Christoph Studerb82bc782014-08-20 14:29:43 +02003624 }
3625
3626 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3627 if (trim == TRIM_LIGHT) {
3628 mLightTrimListeners.add(info);
3629 } else {
3630 mLightTrimListeners.remove(info);
3631 }
3632 }
3633
3634 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
3635 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04003636 }
3637
John Spurlock7340fc82014-04-24 18:50:12 -04003638 /**
3639 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02003640 *
3641 * <p>
3642 * Also takes care of removing a notification that has been visible to a listener before,
3643 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04003644 */
Christoph Studercef37cf2014-07-25 14:18:17 +02003645 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
Christoph Studerb82bc782014-08-20 14:29:43 +02003646 // Lazily initialized snapshots of the notification.
Chris Wren47633422016-01-22 09:56:59 -05003647 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02003648
John Spurlock7340fc82014-04-24 18:50:12 -04003649 for (final ManagedServiceInfo info : mServices) {
Christoph Studercef37cf2014-07-25 14:18:17 +02003650 boolean sbnVisible = isVisibleToListener(sbn, info);
3651 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
3652 // This notification hasn't been and still isn't visible -> ignore.
3653 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02003654 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04003655 }
Chris Wren333a61c2014-05-28 16:40:57 -04003656 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02003657
3658 // This notification became invisible -> remove the old one.
3659 if (oldSbnVisible && !sbnVisible) {
3660 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
3661 mHandler.post(new Runnable() {
3662 @Override
3663 public void run() {
3664 notifyRemoved(info, oldSbnLightClone, update);
3665 }
3666 });
Christoph Studer05ad4822014-05-16 14:16:03 +02003667 continue;
3668 }
Christoph Studercef37cf2014-07-25 14:18:17 +02003669
Chris Wren47633422016-01-22 09:56:59 -05003670 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02003671 mHandler.post(new Runnable() {
3672 @Override
3673 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02003674 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02003675 }
3676 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003677 }
3678 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003679
John Spurlock7340fc82014-04-24 18:50:12 -04003680 /**
3681 * asynchronously notify all listeners about a removed notification
3682 */
Chris Wren333a61c2014-05-28 16:40:57 -04003683 public void notifyRemovedLocked(StatusBarNotification sbn) {
John Spurlock7340fc82014-04-24 18:50:12 -04003684 // make a copy in case changes are made to the underlying Notification object
3685 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
3686 // notification
3687 final StatusBarNotification sbnLight = sbn.cloneLight();
Chris Wrenf9536642014-04-17 10:01:54 -04003688 for (final ManagedServiceInfo info : mServices) {
Christoph Studercef37cf2014-07-25 14:18:17 +02003689 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02003690 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04003691 }
Chris Wren333a61c2014-05-28 16:40:57 -04003692 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02003693 mHandler.post(new Runnable() {
3694 @Override
3695 public void run() {
Christoph Studercef37cf2014-07-25 14:18:17 +02003696 notifyRemoved(info, sbnLight, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02003697 }
3698 });
Chris Wrenf9536642014-04-17 10:01:54 -04003699 }
3700 }
3701
3702 /**
3703 * asynchronously notify all listeners about a reordering of notifications
Chris Wrenf9536642014-04-17 10:01:54 -04003704 */
Chris Wren333a61c2014-05-28 16:40:57 -04003705 public void notifyRankingUpdateLocked() {
Chris Wrenf9536642014-04-17 10:01:54 -04003706 for (final ManagedServiceInfo serviceInfo : mServices) {
Christoph Studer05ad4822014-05-16 14:16:03 +02003707 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3708 continue;
3709 }
Christoph Studercef37cf2014-07-25 14:18:17 +02003710 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
John Spurlock7340fc82014-04-24 18:50:12 -04003711 mHandler.post(new Runnable() {
3712 @Override
3713 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -04003714 notifyRankingUpdate(serviceInfo, update);
John Spurlock7340fc82014-04-24 18:50:12 -04003715 }
3716 });
Kenny Guya263e4e2014-03-03 18:24:03 +00003717 }
Kenny Guya263e4e2014-03-03 18:24:03 +00003718 }
Kenny Guya263e4e2014-03-03 18:24:03 +00003719
John Spurlockd8afe3c2014-08-01 14:04:07 -04003720 public void notifyListenerHintsChangedLocked(final int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04003721 for (final ManagedServiceInfo serviceInfo : mServices) {
3722 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3723 continue;
3724 }
3725 mHandler.post(new Runnable() {
3726 @Override
3727 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003728 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04003729 }
3730 });
3731 }
3732 }
3733
Christoph Studer85a384b2014-08-27 20:16:15 +02003734 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
3735 for (final ManagedServiceInfo serviceInfo : mServices) {
3736 if (!serviceInfo.isEnabledForCurrentProfiles()) {
3737 continue;
3738 }
3739 mHandler.post(new Runnable() {
3740 @Override
3741 public void run() {
3742 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
3743 }
3744 });
3745 }
3746 }
3747
Christoph Studercef37cf2014-07-25 14:18:17 +02003748 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02003749 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
John Spurlock7340fc82014-04-24 18:50:12 -04003750 final INotificationListener listener = (INotificationListener)info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07003751 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04003752 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07003753 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04003754 } catch (RemoteException ex) {
3755 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
3756 }
3757 }
3758
Christoph Studercef37cf2014-07-25 14:18:17 +02003759 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Christoph Studer05ad4822014-05-16 14:16:03 +02003760 NotificationRankingUpdate rankingUpdate) {
John Spurlock7340fc82014-04-24 18:50:12 -04003761 if (!info.enabledAndUserMatches(sbn.getUserId())) {
3762 return;
3763 }
Christoph Studer05ad4822014-05-16 14:16:03 +02003764 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07003765 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04003766 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07003767 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04003768 } catch (RemoteException ex) {
3769 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04003770 }
Kenny Guya263e4e2014-03-03 18:24:03 +00003771 }
Chris Wrenf9536642014-04-17 10:01:54 -04003772
Christoph Studer05ad4822014-05-16 14:16:03 +02003773 private void notifyRankingUpdate(ManagedServiceInfo info,
3774 NotificationRankingUpdate rankingUpdate) {
3775 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04003776 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02003777 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04003778 } catch (RemoteException ex) {
3779 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
3780 }
3781 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003782
John Spurlockd8afe3c2014-08-01 14:04:07 -04003783 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04003784 final INotificationListener listener = (INotificationListener) info.service;
3785 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003786 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04003787 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003788 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04003789 }
3790 }
Justin Koh38156c52014-06-04 13:57:49 -07003791
Christoph Studer85a384b2014-08-27 20:16:15 +02003792 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
3793 int interruptionFilter) {
3794 final INotificationListener listener = (INotificationListener) info.service;
3795 try {
3796 listener.onInterruptionFilterChanged(interruptionFilter);
3797 } catch (RemoteException ex) {
3798 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
3799 }
3800 }
3801
Justin Koh38156c52014-06-04 13:57:49 -07003802 private boolean isListenerPackage(String packageName) {
3803 if (packageName == null) {
3804 return false;
3805 }
3806 // TODO: clean up locking object later
3807 synchronized (mNotificationList) {
3808 for (final ManagedServiceInfo serviceInfo : mServices) {
3809 if (packageName.equals(serviceInfo.component.getPackageName())) {
3810 return true;
3811 }
3812 }
3813 }
3814 return false;
3815 }
Christoph Studer265c1052014-07-23 17:14:33 +02003816
3817 /**
3818 * Returns whether any of the currently registered listeners wants to receive notification
3819 * groups.
3820 *
3821 * <p>Currently we assume groups are desired by non-SystemUI listeners.</p>
3822 */
3823 public boolean notificationGroupsDesired() {
3824 return mNotificationGroupsDesired;
3825 }
3826
3827 private void updateNotificationGroupsDesiredLocked() {
3828 mNotificationGroupsDesired = true;
3829 // No listeners, no groups.
3830 if (mServices.isEmpty()) {
3831 mNotificationGroupsDesired = false;
3832 return;
3833 }
3834 // One listener: Check whether it's SysUI.
3835 if (mServices.size() == 1 &&
3836 mServices.get(0).component.getPackageName().equals("com.android.systemui")) {
3837 mNotificationGroupsDesired = false;
3838 return;
3839 }
3840 }
Kenny Guya263e4e2014-03-03 18:24:03 +00003841 }
John Spurlock25e2d242014-06-27 13:58:23 -04003842
3843 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04003844 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04003845 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04003846 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04003847 public long since;
3848 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04003849 public boolean redact = true;
John Spurlock25e2d242014-06-27 13:58:23 -04003850
3851 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04003852 final DumpFilter filter = new DumpFilter();
3853 for (int ai = 0; ai < args.length; ai++) {
3854 final String a = args[ai];
3855 if ("--noredact".equals(a) || "--reveal".equals(a)) {
3856 filter.redact = false;
3857 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
3858 if (ai < args.length-1) {
3859 ai++;
3860 filter.pkgFilter = args[ai].trim().toLowerCase();
3861 if (filter.pkgFilter.isEmpty()) {
3862 filter.pkgFilter = null;
3863 } else {
3864 filter.filtered = true;
3865 }
3866 }
3867 } else if ("--zen".equals(a) || "zen".equals(a)) {
3868 filter.filtered = true;
3869 filter.zen = true;
3870 } else if ("--stats".equals(a)) {
3871 filter.stats = true;
3872 if (ai < args.length-1) {
3873 ai++;
3874 filter.since = Long.valueOf(args[ai]);
3875 } else {
3876 filter.since = 0;
3877 }
3878 }
John Spurlock25e2d242014-06-27 13:58:23 -04003879 }
Dan Sandlera1770312015-07-10 13:59:29 -04003880 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04003881 }
3882
3883 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04003884 if (!filtered) return true;
3885 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04003886 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04003887 }
3888
3889 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04003890 if (!filtered) return true;
3891 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04003892 }
3893
3894 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04003895 if (!filtered) return true;
3896 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04003897 }
3898
3899 @Override
3900 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04003901 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04003902 }
3903 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07003904
3905 /**
3906 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
3907 * binder without sending large amounts of data over a oneway transaction.
3908 */
3909 private static final class StatusBarNotificationHolder
3910 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07003911 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07003912
3913 public StatusBarNotificationHolder(StatusBarNotification value) {
3914 mValue = value;
3915 }
3916
Griff Hazene9aac5f2014-09-05 20:04:09 -07003917 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07003918 @Override
3919 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07003920 StatusBarNotification value = mValue;
3921 mValue = null;
3922 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07003923 }
3924 }
John Spurlock7c74f782015-06-04 13:01:42 -04003925
3926 private final class PolicyAccess {
3927 private static final String SEPARATOR = ":";
3928 private final String[] PERM = {
3929 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
3930 };
3931
3932 public boolean isPackageGranted(String pkg) {
3933 return pkg != null && getGrantedPackages().contains(pkg);
3934 }
3935
3936 public void put(String pkg, boolean granted) {
3937 if (pkg == null) return;
3938 final ArraySet<String> pkgs = getGrantedPackages();
3939 boolean changed;
3940 if (granted) {
3941 changed = pkgs.add(pkg);
3942 } else {
3943 changed = pkgs.remove(pkg);
3944 }
3945 if (!changed) return;
3946 final String setting = TextUtils.join(SEPARATOR, pkgs);
3947 final int currentUser = ActivityManager.getCurrentUser();
3948 Settings.Secure.putStringForUser(getContext().getContentResolver(),
3949 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
3950 setting,
3951 currentUser);
3952 getContext().sendBroadcastAsUser(new Intent(NotificationManager
3953 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3954 .setPackage(pkg)
3955 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
3956 }
3957
3958 public ArraySet<String> getGrantedPackages() {
3959 final ArraySet<String> pkgs = new ArraySet<>();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04003960
3961 long identity = Binder.clearCallingIdentity();
3962 try {
3963 final String setting = Settings.Secure.getStringForUser(
3964 getContext().getContentResolver(),
3965 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
3966 ActivityManager.getCurrentUser());
3967 if (setting != null) {
3968 final String[] tokens = setting.split(SEPARATOR);
3969 for (int i = 0; i < tokens.length; i++) {
3970 String token = tokens[i];
3971 if (token != null) {
Andreas Gampe1ed71f32015-12-11 15:49:07 -08003972 token = token.trim();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04003973 }
3974 if (TextUtils.isEmpty(token)) {
3975 continue;
3976 }
3977 pkgs.add(token);
John Spurlock7c74f782015-06-04 13:01:42 -04003978 }
John Spurlock7c74f782015-06-04 13:01:42 -04003979 }
Julia Reynoldsea6c4482015-08-13 09:01:33 -04003980 } finally {
3981 Binder.restoreCallingIdentity(identity);
John Spurlock7c74f782015-06-04 13:01:42 -04003982 }
3983 return pkgs;
3984 }
3985
3986 public String[] getRequestingPackages() throws RemoteException {
3987 final ParceledListSlice list = AppGlobals.getPackageManager()
3988 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
3989 ActivityManager.getCurrentUser());
3990 final List<PackageInfo> pkgs = list.getList();
3991 if (pkgs == null || pkgs.isEmpty()) return new String[0];
3992 final int N = pkgs.size();
3993 final String[] rt = new String[N];
3994 for (int i = 0; i < N; i++) {
3995 rt[i] = pkgs.get(i).packageName;
3996 }
3997 return rt;
3998 }
3999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004000}