blob: 4973e17f33bf392774fc06b5f855b9cec87a3477 [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 Wrene0ba7eb2016-03-04 17:30:43 -050019import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL;
20import static android.service.notification.NotificationRankerService.REASON_APP_CANCEL_ALL;
21import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL;
22import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CANCEL_ALL;
23import static android.service.notification.NotificationRankerService.REASON_DELEGATE_CLICK;
24import static android.service.notification.NotificationRankerService.REASON_DELEGATE_ERROR;
Chris Wrene0ba7eb2016-03-04 17:30:43 -050025import static android.service.notification.NotificationRankerService.REASON_GROUP_SUMMARY_CANCELED;
26import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL;
27import static android.service.notification.NotificationRankerService.REASON_LISTENER_CANCEL_ALL;
28import static android.service.notification.NotificationRankerService.REASON_PACKAGE_BANNED;
29import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
30import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
31import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
Julia Reynoldse46bb372016-03-17 11:05:58 -040032import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
Chris Wrene0ba7eb2016-03-04 17:30:43 -050033import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
Jason Monk63506742015-12-16 12:06:51 -050034import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
Bryce Lee7219ada2016-04-08 10:54:23 -070035import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
36import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
Julia Reynoldsd5607292016-02-05 15:25:58 -050037import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
Julia Reynolds61721582016-01-05 08:35:25 -050038import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
Christoph Studerb82bc782014-08-20 14:29:43 +020039import static android.service.notification.NotificationListenerService.TRIM_FULL;
40import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Julia Reynoldsf0f629f2016-02-25 09:34:04 -050041import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
Chris Wren4a4b49d2016-02-09 11:25:08 -050042import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_NONE;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070043
Jeff Sharkey098d5802012-04-26 17:30:34 -070044import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
svetoslavganov75986cf2009-05-14 22:28:01 -070045
Chris Wren51017d02015-12-15 15:34:46 -050046import android.Manifest;
Wei Liu97e56662016-03-04 10:52:33 -080047import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070048import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070049import android.app.ActivityManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.app.ActivityManagerNative;
John Spurlock7340fc82014-04-24 18:50:12 -040051import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050052import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040053import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.app.IActivityManager;
55import android.app.INotificationManager;
56import android.app.ITransientNotification;
57import android.app.Notification;
John Spurlockb4782522014-08-22 14:54:46 -040058import android.app.NotificationManager;
John Spurlock1fc476d2015-04-14 16:05:20 -040059import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.app.PendingIntent;
61import android.app.StatusBarManager;
John Spurlock35ef0a62015-05-28 11:24:10 -040062import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070063import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070064import android.app.usage.UsageStatsManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070066import android.content.ComponentName;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070067import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.content.Context;
69import android.content.Intent;
70import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040071import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +000072import android.content.pm.IPackageManager;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050073import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import android.content.pm.PackageManager;
75import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +020076import android.content.pm.ParceledListSlice;
Chris Wren66189fc2015-06-25 14:04:33 -040077import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070079import android.database.ContentObserver;
John Spurlock7b414672014-07-18 13:02:39 -040080import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -070081import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -050082import android.media.AudioManagerInternal;
Jean-Michel Triviceb79bc2014-09-05 11:09:14 -070083import android.media.AudioSystem;
Jeff Sharkey098d5802012-04-26 17:30:34 -070084import android.media.IRingtonePlayer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.os.Binder;
John Spurlock2b122f42014-08-27 16:29:47 -040087import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -040088import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -040090import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.os.IBinder;
John Spurlock7340fc82014-04-24 18:50:12 -040092import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -040093import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070095import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -070096import android.os.RemoteException;
Chris Wrenc8673a82016-05-17 17:11:29 -040097import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +010098import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070099import android.os.UserHandle;
Chris Wren66189fc2015-06-25 14:04:33 -0400100import android.os.UserManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101import android.os.Vibrator;
102import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400103import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400104import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400105import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400106import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700107import android.service.notification.IStatusBarNotificationHolder;
Chris Wrene0ba7eb2016-03-04 17:30:43 -0500108import android.service.notification.NotificationRankerService;
John Spurlock7340fc82014-04-24 18:50:12 -0400109import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200110import android.service.notification.NotificationRankingUpdate;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700111import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400112import android.service.notification.ZenModeConfig;
John Spurlock32fe4c62014-10-02 12:16:02 -0400113import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500114import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700115import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400116import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400117import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700118import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800120import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700121import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400122import android.util.Xml;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700123import android.view.WindowManager;
124import android.view.WindowManagerInternal;
svetoslavganov75986cf2009-05-14 22:28:01 -0700125import android.view.accessibility.AccessibilityEvent;
126import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000128
Scott Greenwald9a05b312013-06-28 00:37:54 -0400129import com.android.internal.R;
Chris Wren93bb8b82016-03-29 14:35:05 -0400130import com.android.internal.annotations.VisibleForTesting;
Chris Wrend1dbc922015-06-19 17:51:16 -0400131import com.android.internal.statusbar.NotificationVisibility;
John Spurlock056c5192014-04-20 21:52:01 -0400132import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400133import com.android.internal.util.Preconditions;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700134import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800135import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700136import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800137import com.android.server.SystemService;
138import com.android.server.lights.Light;
139import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400140import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700141import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400142import com.android.server.statusbar.StatusBarManagerInternal;
Ruben Brunke24b9a62016-02-16 21:38:24 -0800143import com.android.server.notification.ManagedServices.UserProfiles;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800144
John Spurlockb408e8e2014-04-23 21:12:45 -0400145import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000146
Chris Wrene4b38802015-07-07 15:54:19 -0400147import org.json.JSONException;
148import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700149import org.xmlpull.v1.XmlPullParser;
150import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400151import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700152
John Spurlock35ef0a62015-05-28 11:24:10 -0400153import java.io.ByteArrayInputStream;
154import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400155import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400157import java.io.FileInputStream;
158import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400159import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400160import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400161import java.io.InputStream;
162import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100164import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500165import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166import java.util.ArrayList;
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400167import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500168import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400169import java.util.List;
Chris Wrenacf424a2016-03-15 12:48:55 -0400170import java.util.Map;
Christoph Studer265c1052014-07-23 17:14:33 +0200171import java.util.Map.Entry;
Chris Wren0efdb882016-03-01 17:17:47 -0500172import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500173import java.util.concurrent.TimeUnit;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400174
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400175/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800176public class NotificationManagerService extends SystemService {
177 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100178 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800179 public static final boolean ENABLE_CHILD_NOTIFICATIONS
180 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181
Adam Lesinski182f73f2013-12-05 16:48:06 -0800182 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Chris Wrena61f1792016-08-04 11:24:42 -0400183 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 10f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 // message codes
Adam Lesinski182f73f2013-12-05 16:48:06 -0800186 static final int MESSAGE_TIMEOUT = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400187 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500188 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
189 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
190 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
191
192 // ranking thread messages
193 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
194 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700196 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800197 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800198
Adam Lesinski182f73f2013-12-05 16:48:06 -0800199 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200200
Adam Lesinski182f73f2013-12-05 16:48:06 -0800201 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
Adam Lesinski182f73f2013-12-05 16:48:06 -0800203 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500204
Adam Lesinski182f73f2013-12-05 16:48:06 -0800205 static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
206 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400207
Christoph Studer12aeda82014-09-23 19:08:56 +0200208 // When #matchesCallFilter is called from the ringer, wait at most
209 // 3s to resolve the contacts. This timeout is required since
210 // ContactsProvider might take a long time to start up.
211 //
212 // Return STARRED_CONTACT when the timeout is hit in order to avoid
213 // missed calls in ZEN mode "Important".
214 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
215 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
216 ValidateNotificationPeople.STARRED_CONTACT;
217
Christoph Studer265c1052014-07-23 17:14:33 +0200218 /** notification_enqueue status value for a newly enqueued notification. */
219 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
220
221 /** notification_enqueue status value for an existing notification. */
222 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
223
224 /** notification_enqueue status value for an ignored notification. */
225 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400226 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Chris Wren0efdb882016-03-01 17:17:47 -0500227 private String mRankerServicePackageName;
Christoph Studer265c1052014-07-23 17:14:33 +0200228
Adam Lesinski182f73f2013-12-05 16:48:06 -0800229 private IActivityManager mAm;
230 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500231 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800232 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800233 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700234 private WindowManagerInternal mWindowManagerInternal;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 final IBinder mForegroundToken = new Binder();
Chris Wren93bb8b82016-03-29 14:35:05 -0400237 private Handler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400238 private final HandlerThread mRankingThread = new HandlerThread("ranker",
239 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
Adam Lesinski182f73f2013-12-05 16:48:06 -0800241 private Light mNotificationLight;
242 Light mAttentionLight;
Mike Lockwood670f9322010-01-20 12:13:36 -0500243 private int mDefaultNotificationColor;
244 private int mDefaultNotificationLedOn;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800245
Mike Lockwood670f9322010-01-20 12:13:36 -0500246 private int mDefaultNotificationLedOff;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800247 private long[] mDefaultVibrationPattern;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800248
Daniel Sandleredbb3802012-11-13 20:49:47 -0800249 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400250 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800251 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800252
John Spurlockd8afe3c2014-08-01 14:04:07 -0400253 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400254 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500255 private String mSoundNotificationKey;
256 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257
Bryce Lee7219ada2016-04-08 10:54:23 -0700258 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
259 new SparseArray<ArraySet<ManagedServiceInfo>>();
260 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400261 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500262 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400263
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500264 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400265 private boolean mScreenOn = true;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500266 private boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500267 private boolean mNotificationPulseEnabled;
268
Daniel Sandler09a247e2013-02-14 10:24:17 -0500269 // used as a mutex for access to all active notifications & listeners
Adam Lesinski182f73f2013-12-05 16:48:06 -0800270 final ArrayList<NotificationRecord> mNotificationList =
Fred Quintana6ecaff12009-09-25 14:23:13 -0700271 new ArrayList<NotificationRecord>();
John Spurlocka4294292014-03-24 18:02:32 -0400272 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
273 new ArrayMap<String, NotificationRecord>();
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400274 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800275 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
Christoph Studer265c1052014-07-23 17:14:33 +0200276 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
John Spurlock7c74f782015-06-04 13:01:42 -0400277 final PolicyAccess mPolicyAccess = new PolicyAccess();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
Chris Wren6054e612014-11-25 17:16:46 -0500279 // The last key in this list owns the hardware.
280 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700281
Adam Lesinski182f73f2013-12-05 16:48:06 -0800282 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700283 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500284
Griff Hazen9f637d12014-06-10 11:13:51 -0700285 private Archive mArchive;
286
John Spurlock21258a32015-05-27 18:22:55 -0400287 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400288 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400289
Daniel Sandler0da673f2012-04-11 12:33:16 -0400290 private static final int DB_VERSION = 1;
291
John Spurlock21258a32015-05-27 18:22:55 -0400292 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400293 private static final String ATTR_VERSION = "version";
294
Chris Wren54bbef42014-07-09 18:37:56 -0400295 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400296
John Spurlockb408e8e2014-04-23 21:12:45 -0400297 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400298 private NotificationListeners mListeners;
Chris Wren0efdb882016-03-01 17:17:47 -0500299 private NotificationRankers mRankerServices;
John Spurlock7340fc82014-04-24 18:50:12 -0400300 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200301 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100302
John Spurlocke6a7d932014-03-13 12:29:00 -0400303 private static final int MY_UID = Process.myUid();
304 private static final int MY_PID = Process.myPid();
Chris Wren51017d02015-12-15 15:34:46 -0500305 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400306 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400307 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
Chris Wrend4054312016-06-24 17:07:40 -0400308 private String mSystemNotificationSound;
John Spurlocke6a7d932014-03-13 12:29:00 -0400309
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500310 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700311 final int mBufferSize;
312 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500313
Griff Hazen9f637d12014-06-10 11:13:51 -0700314 public Archive(int size) {
315 mBufferSize = size;
316 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500317 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700318
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400319 public String toString() {
320 final StringBuilder sb = new StringBuilder();
321 final int N = mBuffer.size();
322 sb.append("Archive (");
323 sb.append(N);
324 sb.append(" notification");
325 sb.append((N==1)?")":"s)");
326 return sb.toString();
327 }
328
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500329 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700330 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500331 mBuffer.removeFirst();
332 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400333
334 // We don't want to store the heavy bits of the notification in the archive,
335 // but other clients in the system process might be using the object, so we
336 // store a (lightened) copy.
337 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500338 }
339
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500340 public Iterator<StatusBarNotification> descendingIterator() {
341 return mBuffer.descendingIterator();
342 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500343
344 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700345 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500346 final StatusBarNotification[] a
347 = new StatusBarNotification[Math.min(count, mBuffer.size())];
348 Iterator<StatusBarNotification> iter = descendingIterator();
349 int i=0;
350 while (iter.hasNext() && i < count) {
351 a[i++] = iter.next();
352 }
353 return a;
354 }
355
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500356 }
357
John Spurlock35ef0a62015-05-28 11:24:10 -0400358 private void readPolicyXml(InputStream stream, boolean forRestore)
359 throws XmlPullParserException, NumberFormatException, IOException {
360 final XmlPullParser parser = Xml.newPullParser();
361 parser.setInput(stream, StandardCharsets.UTF_8.name());
362
Chris Wrenacf424a2016-03-15 12:48:55 -0400363 while (parser.next() != END_DOCUMENT) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400364 mZenModeHelper.readXml(parser, forRestore);
365 mRankingHelper.readXml(parser, forRestore);
366 }
367 }
368
John Spurlock056c5192014-04-20 21:52:01 -0400369 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400370 if (DBG) Slog.d(TAG, "loadPolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400371 synchronized(mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400372
John Spurlock056c5192014-04-20 21:52:01 -0400373 FileInputStream infile = null;
374 try {
375 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400376 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400377 } catch (FileNotFoundException e) {
378 // No data yet
379 } catch (IOException e) {
380 Log.wtf(TAG, "Unable to read notification policy", e);
381 } catch (NumberFormatException e) {
382 Log.wtf(TAG, "Unable to parse notification policy", e);
383 } catch (XmlPullParserException e) {
384 Log.wtf(TAG, "Unable to parse notification policy", e);
385 } finally {
386 IoUtils.closeQuietly(infile);
387 }
388 }
389 }
390
391 public void savePolicyFile() {
392 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
393 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
394 }
395
396 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400397 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400398 synchronized (mPolicyFile) {
399 final FileOutputStream stream;
400 try {
401 stream = mPolicyFile.startWrite();
402 } catch (IOException e) {
403 Slog.w(TAG, "Failed to save policy file", e);
404 return;
405 }
406
407 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400408 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400409 mPolicyFile.finishWrite(stream);
410 } catch (IOException e) {
411 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
412 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400413 }
414 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400415 BackupManager.dataChanged(getContext().getPackageName());
416 }
417
418 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
419 final XmlSerializer out = new FastXmlSerializer();
420 out.setOutput(stream, StandardCharsets.UTF_8.name());
421 out.startDocument(null, true);
422 out.startTag(null, TAG_NOTIFICATION_POLICY);
423 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
424 mZenModeHelper.writeXml(out, forBackup);
425 mRankingHelper.writeXml(out, forBackup);
426 out.endTag(null, TAG_NOTIFICATION_POLICY);
427 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400428 }
429
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500430 /** Use this when you actually want to post a notification or toast.
431 *
432 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
433 */
434 private boolean noteNotificationOp(String pkg, int uid) {
435 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
436 != AppOpsManager.MODE_ALLOWED) {
437 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
438 return false;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400439 }
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500440 return true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400441 }
442
Chris Wren66189fc2015-06-25 14:04:33 -0400443 /** Use this to check if a package can post a notification or toast. */
444 private boolean checkNotificationOp(String pkg, int uid) {
445 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000446 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
Chris Wren66189fc2015-06-25 14:04:33 -0400447 }
448
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 private static final class ToastRecord
450 {
451 final int pid;
452 final String pkg;
453 final ITransientNotification callback;
454 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700455 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700457 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
458 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 this.pid = pid;
460 this.pkg = pkg;
461 this.callback = callback;
462 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700463 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 }
465
466 void update(int duration) {
467 this.duration = duration;
468 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800469
John Spurlock25e2d242014-06-27 13:58:23 -0400470 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
471 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 pw.println(prefix + this);
473 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475 @Override
476 public final String toString()
477 {
478 return "ToastRecord{"
479 + Integer.toHexString(System.identityHashCode(this))
480 + " pkg=" + pkg
481 + " callback=" + callback
482 + " duration=" + duration;
483 }
484 }
485
Adam Lesinski182f73f2013-12-05 16:48:06 -0800486 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487
Adam Lesinski182f73f2013-12-05 16:48:06 -0800488 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 public void onSetDisabled(int status) {
490 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400491 mDisableNotificationEffects =
492 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400493 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 // cancel whatever's going on
495 long identity = Binder.clearCallingIdentity();
496 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800497 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700498 if (player != null) {
499 player.stopAsync();
500 }
501 } catch (RemoteException e) {
502 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 Binder.restoreCallingIdentity(identity);
504 }
505
506 identity = Binder.clearCallingIdentity();
507 try {
508 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700509 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 Binder.restoreCallingIdentity(identity);
511 }
512 }
513 }
514 }
515
Adam Lesinski182f73f2013-12-05 16:48:06 -0800516 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400517 public void onClearAll(int callingUid, int callingPid, int userId) {
Adam Lesinskie8240262014-03-26 16:01:00 -0700518 synchronized (mNotificationList) {
Kenny Guya263e4e2014-03-03 18:24:03 +0000519 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
520 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700521 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 }
523
Adam Lesinski182f73f2013-12-05 16:48:06 -0800524 @Override
Christoph Studer03b87a22014-04-30 17:33:27 +0200525 public void onNotificationClick(int callingUid, int callingPid, String key) {
526 synchronized (mNotificationList) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200527 NotificationRecord r = mNotificationsByKey.get(key);
528 if (r == null) {
529 Log.w(TAG, "No notification with key: " + key);
530 return;
531 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400532 final long now = System.currentTimeMillis();
533 EventLogTags.writeNotificationClicked(key,
534 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
535
Christoph Studer03b87a22014-04-30 17:33:27 +0200536 StatusBarNotification sbn = r.sbn;
537 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
538 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
539 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
540 REASON_DELEGATE_CLICK, null);
541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 }
543
Adam Lesinski182f73f2013-12-05 16:48:06 -0800544 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200545 public void onNotificationActionClick(int callingUid, int callingPid, String key,
546 int actionIndex) {
547 synchronized (mNotificationList) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200548 NotificationRecord r = mNotificationsByKey.get(key);
549 if (r == null) {
550 Log.w(TAG, "No notification with key: " + key);
551 return;
552 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400553 final long now = System.currentTimeMillis();
554 EventLogTags.writeNotificationActionClicked(key, actionIndex,
555 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Christoph Studer4da84cd2014-10-21 17:24:20 +0200556 // TODO: Log action click via UsageStats.
557 }
558 }
559
560 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400561 public void onNotificationClear(int callingUid, int callingPid,
562 String pkg, String tag, int id, int userId) {
563 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000564 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
John Spurlocke6a7d932014-03-13 12:29:00 -0400565 true, userId, REASON_DELEGATE_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400566 }
567
Adam Lesinski182f73f2013-12-05 16:48:06 -0800568 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400569 public void onPanelRevealed(boolean clearEffects, int items) {
570 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100571 if (clearEffects) {
572 clearEffects();
573 }
574 }
575
576 @Override
577 public void onPanelHidden() {
578 EventLogTags.writeNotificationPanelHidden();
579 }
580
581 @Override
582 public void clearEffects() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 synchronized (mNotificationList) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100584 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400585 clearSoundLocked();
586 clearVibrateLocked();
587 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
589 }
Joe Onorato005847b2010-06-04 16:08:02 -0400590
Adam Lesinski182f73f2013-12-05 16:48:06 -0800591 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400592 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000593 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400594 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
595 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400596 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
597 REASON_DELEGATE_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700598 long ident = Binder.clearCallingIdentity();
599 try {
600 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
601 "Bad notification posted from package " + pkg
602 + ": " + message);
603 } catch (RemoteException e) {
604 }
605 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400606 }
John Spurlocke677d712014-02-13 12:52:19 -0500607
608 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400609 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
610 NotificationVisibility[] noLongerVisibleKeys) {
Christoph Studerffeb0c32014-05-07 22:23:56 +0200611 synchronized (mNotificationList) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400612 for (NotificationVisibility nv : newlyVisibleKeys) {
613 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200614 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400615 r.setVisibility(true, nv.rank);
616 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200617 }
618 // Note that we might receive this event after notifications
619 // have already left the system, e.g. after dismissing from the
620 // shade. Hence not finding notifications in
621 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400622 for (NotificationVisibility nv : noLongerVisibleKeys) {
623 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200624 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400625 r.setVisibility(false, nv.rank);
626 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200627 }
628 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200629 }
Chris Wren78403d72014-07-28 10:23:24 +0100630
631 @Override
632 public void onNotificationExpansionChanged(String key,
633 boolean userAction, boolean expanded) {
Chris Wren78403d72014-07-28 10:23:24 +0100634 synchronized (mNotificationList) {
635 NotificationRecord r = mNotificationsByKey.get(key);
636 if (r != null) {
637 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400638 final long now = System.currentTimeMillis();
639 EventLogTags.writeNotificationExpansion(key,
640 userAction ? 1 : 0, expanded ? 1 : 0,
641 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100642 }
643 }
644 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 };
646
Chris Wren93bb8b82016-03-29 14:35:05 -0400647 private void clearSoundLocked() {
648 mSoundNotificationKey = null;
649 long identity = Binder.clearCallingIdentity();
650 try {
651 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
652 if (player != null) {
653 player.stopAsync();
654 }
655 } catch (RemoteException e) {
656 } finally {
657 Binder.restoreCallingIdentity(identity);
658 }
659 }
660
661 private void clearVibrateLocked() {
662 mVibrateNotificationKey = null;
663 long identity = Binder.clearCallingIdentity();
664 try {
665 mVibrator.cancel();
666 } finally {
667 Binder.restoreCallingIdentity(identity);
668 }
669 }
670
671 private void clearLightsLocked() {
672 // light
673 mLights.clear();
674 updateLightsLocked();
675 }
676
Kenny Guy70058402014-10-28 20:45:06 +0000677 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 @Override
679 public void onReceive(Context context, Intent intent) {
680 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -0800681 if (action == null) {
682 return;
683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800685 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -0400686 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -0400687 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -0400688 boolean cancelNotifications = true;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000689 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -0400690
Chris Wren3da73022013-05-10 14:41:21 -0400691 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -0400692 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800693 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -0400694 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800695 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000696 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
697 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +0000698 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
699 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800700 String pkgList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -0400701 boolean removingPackage = queryRemove &&
702 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
703 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800704 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800705 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000706 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
707 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
708 reason = REASON_PACKAGE_SUSPENDED;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800709 } else if (queryRestart) {
710 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800711 } else {
712 Uri uri = intent.getData();
713 if (uri == null) {
714 return;
715 }
716 String pkgName = uri.getSchemeSpecificPart();
717 if (pkgName == null) {
718 return;
719 }
Daniel Sandler26ece572012-06-01 15:38:46 -0400720 if (packageChanged) {
721 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -0700722 try {
Kenny Guy70058402014-10-28 20:45:06 +0000723 final IPackageManager pm = AppGlobals.getPackageManager();
724 final int enabled = pm.getApplicationEnabledSetting(pkgName,
725 changeUserId != UserHandle.USER_ALL ? changeUserId :
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700726 UserHandle.USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -0700727 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
728 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
729 cancelNotifications = false;
730 }
731 } catch (IllegalArgumentException e) {
732 // Package doesn't exist; probably racing with uninstall.
733 // cancelNotifications is already true, so nothing to do here.
734 if (DBG) {
735 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
736 }
Kenny Guy70058402014-10-28 20:45:06 +0000737 } catch (RemoteException e) {
738 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -0400739 }
740 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800741 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 }
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700743
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800744 if (pkgList != null && (pkgList.length > 0)) {
745 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -0400746 if (cancelNotifications) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400747 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500748 changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -0400749 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 }
Julia Reynolds6434eb22016-08-08 17:19:26 -0400752 mListeners.onPackagesChanged(removingPackage, pkgList);
753 mRankerServices.onPackagesChanged(removingPackage, pkgList);
754 mConditionProviders.onPackagesChanged(removingPackage, pkgList);
755 mRankingHelper.onPackagesChanged(removingPackage, pkgList);
Kenny Guy70058402014-10-28 20:45:06 +0000756 }
757 }
758 };
759
760 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
761 @Override
762 public void onReceive(Context context, Intent intent) {
763 String action = intent.getAction();
764
765 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400766 // Keep track of screen on/off state, but do not turn off the notification light
767 // until user passes through the lock screen or views the notification.
768 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +0100769 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400770 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
771 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +0100772 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500773 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -0500774 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
775 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500776 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700777 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
778 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
779 if (userHandle >= 0) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400780 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500781 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700782 }
Rubin Xue95057a2016-04-01 16:49:25 +0100783 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000784 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +0100785 if (userHandle >= 0) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000786 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500787 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000788 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400789 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
790 // turn off LED when user passes through lock screen
791 mNotificationLight.turnOff();
Wei Liu97e56662016-03-04 10:52:33 -0800792 if (mStatusBar != null) {
793 mStatusBar.notificationLightOff();
794 }
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400795 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
John Spurlock1b8b22b2015-05-20 09:47:13 -0400796 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400797 // reload per-user settings
798 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -0400799 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200800 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -0400801 mConditionProviders.onUserSwitched(user);
802 mListeners.onUserSwitched(user);
Chris Wrene0ba7eb2016-03-04 17:30:43 -0500803 mRankerServices.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -0400804 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000805 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
John Spurlockb408e8e2014-04-23 21:12:45 -0400806 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -0400807 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
808 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
809 mZenModeHelper.onUserRemoved(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500810 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
811 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
812 mConditionProviders.onUserUnlocked(user);
813 mListeners.onUserUnlocked(user);
Chris Wrene0ba7eb2016-03-04 17:30:43 -0500814 mRankerServices.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500815 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 }
817 }
818 };
819
John Spurlock7c74f782015-06-04 13:01:42 -0400820 private final class SettingsObserver extends ContentObserver {
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400821 private final Uri NOTIFICATION_LIGHT_PULSE_URI
822 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wrend4054312016-06-24 17:07:40 -0400823 private final Uri NOTIFICATION_SOUND_URI
824 = Settings.System.getUriFor(Settings.System.NOTIFICATION_SOUND);
Chris Wren763a9bb2016-05-31 17:14:12 -0400825 private final Uri NOTIFICATION_RATE_LIMIT_URI
826 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400827
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700828 SettingsObserver(Handler handler) {
829 super(handler);
830 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800831
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700832 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800833 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400834 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700835 false, this, UserHandle.USER_ALL);
Chris Wrend4054312016-06-24 17:07:40 -0400836 resolver.registerContentObserver(NOTIFICATION_SOUND_URI,
837 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -0400838 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
839 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400840 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700841 }
842
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400843 @Override public void onChange(boolean selfChange, Uri uri) {
844 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700845 }
846
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400847 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800848 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400849 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
850 boolean pulseEnabled = Settings.System.getInt(resolver,
851 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
852 if (mNotificationPulseEnabled != pulseEnabled) {
853 mNotificationPulseEnabled = pulseEnabled;
854 updateNotificationPulse();
855 }
856 }
Chris Wren763a9bb2016-05-31 17:14:12 -0400857 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
858 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
859 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
860 }
Chris Wrend4054312016-06-24 17:07:40 -0400861 if (uri == null || NOTIFICATION_SOUND_URI.equals(uri)) {
862 mSystemNotificationSound = Settings.System.getString(resolver,
863 Settings.System.NOTIFICATION_SOUND);
864 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700865 }
866 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500867
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400868 private SettingsObserver mSettingsObserver;
John Spurlock056c5192014-04-20 21:52:01 -0400869 private ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400870
John Spurlockcad57682014-07-26 17:09:56 -0400871 private final Runnable mBuzzBeepBlinked = new Runnable() {
872 @Override
873 public void run() {
Wei Liu97e56662016-03-04 10:52:33 -0800874 if (mStatusBar != null) {
875 mStatusBar.buzzBeepBlinked();
876 }
John Spurlockcad57682014-07-26 17:09:56 -0400877 }
878 };
879
Daniel Sandleredbb3802012-11-13 20:49:47 -0800880 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
881 int[] ar = r.getIntArray(resid);
882 if (ar == null) {
883 return def;
884 }
885 final int len = ar.length > maxlen ? maxlen : ar.length;
886 long[] out = new long[len];
887 for (int i=0; i<len; i++) {
888 out[i] = ar[i];
889 }
890 return out;
891 }
892
Jeff Brownb880d882014-02-10 19:47:07 -0800893 public NotificationManagerService(Context context) {
894 super(context);
895 }
896
Chris Wren93bb8b82016-03-29 14:35:05 -0400897 @VisibleForTesting
898 void setAudioManager(AudioManager audioMananger) {
899 mAudioManager = audioMananger;
900 }
901
902 @VisibleForTesting
903 void setVibrator(Vibrator vibrator) {
904 mVibrator = vibrator;
905 }
906
907 @VisibleForTesting
908 void setSystemReady(boolean systemReady) {
909 mSystemReady = systemReady;
910 }
911
912 @VisibleForTesting
913 void setHandler(Handler handler) {
914 mHandler = handler;
915 }
916
Chris Wrend4054312016-06-24 17:07:40 -0400917 @VisibleForTesting
918 void setSystemNotificationSound(String systemNotificationSound) {
919 mSystemNotificationSound = systemNotificationSound;
920 }
921
Adam Lesinski182f73f2013-12-05 16:48:06 -0800922 @Override
923 public void onStart() {
Chris Wren54bbef42014-07-09 18:37:56 -0400924 Resources resources = getContext().getResources();
925
Chris Wren763a9bb2016-05-31 17:14:12 -0400926 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
927 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
928 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 mAm = ActivityManagerNative.getDefault();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800931 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
932 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700933 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
San Mehat3ee13172010-02-04 20:54:43 -0800934
Chris Wren0efdb882016-03-01 17:17:47 -0500935 // This is the package that contains the AOSP framework update.
936 mRankerServicePackageName = getContext().getPackageManager()
937 .getServicesSystemSharedLibraryPackageName();
938
Adam Lesinski182f73f2013-12-05 16:48:06 -0800939 mHandler = new WorkerHandler();
Chris Wrenf9536642014-04-17 10:01:54 -0400940 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -0400941 String[] extractorNames;
942 try {
943 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
944 } catch (Resources.NotFoundException e) {
945 extractorNames = new String[0];
946 }
Chris Wren5eab2b72015-06-16 13:56:22 -0400947 mUsageStats = new NotificationUsageStats(getContext());
Chris Wren51017d02015-12-15 15:34:46 -0500948 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Chris Wren54bbef42014-07-09 18:37:56 -0400949 mRankingHelper = new RankingHelper(getContext(),
Chris Wren51017d02015-12-15 15:34:46 -0500950 mRankingHandler,
Chris Wren5eab2b72015-06-16 13:56:22 -0400951 mUsageStats,
Chris Wren54bbef42014-07-09 18:37:56 -0400952 extractorNames);
John Spurlockb2278d62015-04-07 12:47:12 -0400953 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
954 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -0400955 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -0400956 @Override
957 public void onConfigChanged() {
958 savePolicyFile();
959 }
John Spurlockd8afe3c2014-08-01 14:04:07 -0400960
961 @Override
962 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -0400963 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -0500964 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -0500965 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
966 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -0500967 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400968 synchronized(mNotificationList) {
Christoph Studer85a384b2014-08-27 20:16:15 +0200969 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400970 }
971 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400972
973 @Override
974 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -0400975 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
976 }
John Spurlock056c5192014-04-20 21:52:01 -0400977 });
978 final File systemDir = new File(Environment.getDataDirectory(), "system");
979 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500980
Chris Wrenacf424a2016-03-15 12:48:55 -0400981 syncBlockDb();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400982
Chris Wren0efdb882016-03-01 17:17:47 -0500983 // This is a MangedServices object that keeps track of the listeners.
John Spurlock7340fc82014-04-24 18:50:12 -0400984 mListeners = new NotificationListeners();
Chris Wren0efdb882016-03-01 17:17:47 -0500985
986 // This is a MangedServices object that keeps track of the ranker.
987 mRankerServices = new NotificationRankers();
988 // Find the updatable ranker and register it.
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400989 mRankerServices.registerRanker();
Chris Wren0efdb882016-03-01 17:17:47 -0500990
Adam Lesinski182f73f2013-12-05 16:48:06 -0800991 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -0800992 if (mStatusBar != null) {
993 mStatusBar.setNotificationDelegate(mNotificationDelegate);
994 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995
Adam Lesinski182f73f2013-12-05 16:48:06 -0800996 final LightsManager lights = getLocalService(LightsManager.class);
997 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
998 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -0500999
Mike Lockwood670f9322010-01-20 12:13:36 -05001000 mDefaultNotificationColor = resources.getColor(
Scott Greenwald9a05b312013-06-28 00:37:54 -04001001 R.color.config_defaultNotificationColor);
Mike Lockwood670f9322010-01-20 12:13:36 -05001002 mDefaultNotificationLedOn = resources.getInteger(
Scott Greenwald9a05b312013-06-28 00:37:54 -04001003 R.integer.config_defaultNotificationLedOn);
Mike Lockwood670f9322010-01-20 12:13:36 -05001004 mDefaultNotificationLedOff = resources.getInteger(
Scott Greenwald9a05b312013-06-28 00:37:54 -04001005 R.integer.config_defaultNotificationLedOff);
Mike Lockwood670f9322010-01-20 12:13:36 -05001006
Daniel Sandleredbb3802012-11-13 20:49:47 -08001007 mDefaultVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001008 R.array.config_defaultNotificationVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001009 VIBRATE_PATTERN_MAXLEN,
1010 DEFAULT_VIBRATE_PATTERN);
1011
1012 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001013 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001014 VIBRATE_PATTERN_MAXLEN,
1015 DEFAULT_VIBRATE_PATTERN);
1016
Chris Wren5116a822014-06-04 15:59:50 -04001017 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1018
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001019 // Don't start allowing notifications until the setup wizard has run once.
1020 // After that, including subsequent boots, init with notifications turned on.
1021 // This works on the first boot because the setup wizard will toggle this
1022 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001023 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001024 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001025 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001026 }
John Spurlockb2278d62015-04-07 12:47:12 -04001027 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001028 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001029
John Spurlockb408e8e2014-04-23 21:12:45 -04001030 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001031 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001032
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001033 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001034 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001035 filter.addAction(Intent.ACTION_SCREEN_ON);
1036 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001037 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001038 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001039 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001040 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001041 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001042 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001043 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001044 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001045 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001046
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001047 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001048 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001049 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001050 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001051 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1052 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1053 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001054 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1055 null);
1056
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001057 IntentFilter suspendedPkgFilter = new IntentFilter();
1058 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1059 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1060 suspendedPkgFilter, null, null);
1061
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001062 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001063 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1064 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001065
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001066 mSettingsObserver = new SettingsObserver(mHandler);
Scott Greenwald9a05b312013-06-28 00:37:54 -04001067
Griff Hazen9f637d12014-06-10 11:13:51 -07001068 mArchive = new Archive(resources.getInteger(
1069 R.integer.config_notificationServiceArchiveSize));
1070
Adam Lesinski182f73f2013-12-05 16:48:06 -08001071 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1072 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 }
1074
John Spurlocke7a835b2015-05-13 10:47:05 -04001075 private void sendRegisteredOnlyBroadcast(String action) {
1076 getContext().sendBroadcastAsUser(new Intent(action)
1077 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1078 }
1079
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001080 /**
Chris Wrenacf424a2016-03-15 12:48:55 -04001081 * Make sure the XML config and the the AppOps system agree about blocks.
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001082 */
Chris Wrenacf424a2016-03-15 12:48:55 -04001083 private void syncBlockDb() {
John Spurlock056c5192014-04-20 21:52:01 -04001084 loadPolicyFile();
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001085
Chris Wrenacf424a2016-03-15 12:48:55 -04001086 // sync bans from ranker into app opps
1087 Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1088 for(Entry<Integer, String> ban : packageBans.entrySet()) {
1089 final int uid = ban.getKey();
1090 final String packageName = ban.getValue();
1091 setNotificationsEnabledForPackageImpl(packageName, uid, false);
1092 }
1093
1094 // sync bans from app opps into ranker
1095 packageBans.clear();
1096 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1097 final int userId = user.getUserHandle().getIdentifier();
1098 final PackageManager packageManager = getContext().getPackageManager();
1099 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1100 final int packageCount = packages.size();
1101 for (int p = 0; p < packageCount; p++) {
1102 final String packageName = packages.get(p).packageName;
1103 try {
1104 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1105 if (!checkNotificationOp(packageName, uid)) {
1106 packageBans.put(uid, packageName);
1107 }
1108 } catch (NameNotFoundException e) {
1109 // forget you
1110 }
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001111 }
1112 }
Chris Wrenacf424a2016-03-15 12:48:55 -04001113 for (Entry<Integer, String> ban : packageBans.entrySet()) {
1114 mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1115 }
1116
1117 savePolicyFile();
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001118 }
1119
Adam Lesinski182f73f2013-12-05 16:48:06 -08001120 @Override
1121 public void onBootPhase(int phase) {
1122 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1123 // no beeping until we're basically done booting
1124 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001125
Adam Lesinski182f73f2013-12-05 16:48:06 -08001126 // Grab our optional AudioService
1127 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001128 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001129 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001130 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001131 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1132 // This observer will force an update when observe is called, causing us to
1133 // bind to listener services.
1134 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001135 mListeners.onBootPhaseAppsCanStart();
Chris Wrene0ba7eb2016-03-04 17:30:43 -05001136 mRankerServices.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001137 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 }
1139 }
1140
Adam Lesinski182f73f2013-12-05 16:48:06 -08001141 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1142 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143
Adam Lesinski182f73f2013-12-05 16:48:06 -08001144 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1145 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146
Adam Lesinski182f73f2013-12-05 16:48:06 -08001147 // Now, cancel any outstanding notifications that are part of a just-disabled app
1148 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001149 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
Julia Reynoldsef37f282016-02-12 09:11:27 -05001150 REASON_PACKAGE_BANNED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 }
1152 }
1153
John Spurlockd8afe3c2014-08-01 14:04:07 -04001154 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001155 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001156 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001157 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001158 mListenerHints = hints;
1159 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001160 }
1161
John Spurlockb4782522014-08-22 14:54:46 -04001162 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001163 final long updatedSuppressedEffects = calculateSuppressedEffects();
1164 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1165 final List<ComponentName> suppressors = getSuppressors();
1166 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1167 mEffectsSuppressors = suppressors;
1168 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001169 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001170 }
1171
Bryce Lee7219ada2016-04-08 10:54:23 -07001172 private ArrayList<ComponentName> getSuppressors() {
1173 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1174 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1175 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1176
1177 for (ManagedServiceInfo info : serviceInfoList) {
1178 names.add(info.component);
1179 }
1180 }
1181
1182 return names;
1183 }
1184
1185 private boolean removeDisabledHints(ManagedServiceInfo info) {
1186 return removeDisabledHints(info, 0);
1187 }
1188
1189 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1190 boolean removed = false;
1191
1192 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1193 final int hint = mListenersDisablingEffects.keyAt(i);
1194 final ArraySet<ManagedServiceInfo> listeners =
1195 mListenersDisablingEffects.valueAt(i);
1196
1197 if (hints == 0 || (hint & hints) == hint) {
1198 removed = removed || listeners.remove(info);
1199 }
1200 }
1201
1202 return removed;
1203 }
1204
1205 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1206 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1207 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1208 }
1209
1210 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1211 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1212 }
1213
1214 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1215 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1216 }
1217 }
1218
1219 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1220 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1221 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1222 }
1223
1224 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1225 hintListeners.add(info);
1226 }
1227
1228 private int calculateHints() {
1229 int hints = 0;
1230 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1231 int hint = mListenersDisablingEffects.keyAt(i);
1232 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1233
1234 if (!serviceInfoList.isEmpty()) {
1235 hints |= hint;
1236 }
1237 }
1238
1239 return hints;
1240 }
1241
1242 private long calculateSuppressedEffects() {
1243 int hints = calculateHints();
1244 long suppressedEffects = 0;
1245
1246 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1247 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1248 }
1249
1250 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1251 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1252 }
1253
1254 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1255 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1256 }
1257
1258 return suppressedEffects;
1259 }
1260
Christoph Studer85a384b2014-08-27 20:16:15 +02001261 private void updateInterruptionFilterLocked() {
1262 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1263 if (interruptionFilter == mInterruptionFilter) return;
1264 mInterruptionFilter = interruptionFilter;
1265 scheduleInterruptionFilterChanged(interruptionFilter);
1266 }
1267
Adam Lesinski182f73f2013-12-05 16:48:06 -08001268 private final IBinder mService = new INotificationManager.Stub() {
1269 // Toasts
1270 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001273 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001275 if (DBG) {
1276 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1277 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001279
1280 if (pkg == null || callback == null) {
1281 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1282 return ;
1283 }
1284
John Spurlock7340fc82014-04-24 18:50:12 -04001285 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001286 final boolean isPackageSuspended =
1287 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001288
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001289 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001290 || isPackageSuspended)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001291 if (!isSystemToast) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001292 Slog.e(TAG, "Suppressing toast from package " + pkg
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001293 + (isPackageSuspended
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001294 ? " due to package suspended by administrator."
1295 : " by user request."));
Adam Lesinski182f73f2013-12-05 16:48:06 -08001296 return;
1297 }
1298 }
1299
1300 synchronized (mToastQueue) {
1301 int callingPid = Binder.getCallingPid();
1302 long callingId = Binder.clearCallingIdentity();
1303 try {
1304 ToastRecord record;
1305 int index = indexOfToastLocked(pkg, callback);
1306 // If it's already in the queue, we update it in place, we don't
1307 // move it to the end of the queue.
1308 if (index >= 0) {
1309 record = mToastQueue.get(index);
1310 record.update(duration);
1311 } else {
1312 // Limit the number of toasts that any given package except the android
1313 // package can enqueue. Prevents DOS attacks and deals with leaks.
1314 if (!isSystemToast) {
1315 int count = 0;
1316 final int N = mToastQueue.size();
1317 for (int i=0; i<N; i++) {
1318 final ToastRecord r = mToastQueue.get(i);
1319 if (r.pkg.equals(pkg)) {
1320 count++;
1321 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1322 Slog.e(TAG, "Package has already posted " + count
1323 + " toasts. Not showing more. Package=" + pkg);
1324 return;
1325 }
1326 }
1327 }
1328 }
1329
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001330 Binder token = new Binder();
1331 mWindowManagerInternal.addWindowToken(token,
1332 WindowManager.LayoutParams.TYPE_TOAST);
1333 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001334 mToastQueue.add(record);
1335 index = mToastQueue.size() - 1;
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001336 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001337 }
1338 // If it's at index 0, it's the current toast. It doesn't matter if it's
1339 // new or just been updated. Call back and tell it to show itself.
1340 // If the callback fails, this will remove it from the list, so don't
1341 // assume that it's valid after this.
1342 if (index == 0) {
1343 showNextToastLocked();
1344 }
1345 } finally {
1346 Binder.restoreCallingIdentity(callingId);
1347 }
1348 }
1349 }
1350
1351 @Override
1352 public void cancelToast(String pkg, ITransientNotification callback) {
1353 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1354
1355 if (pkg == null || callback == null) {
1356 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1357 return ;
1358 }
1359
1360 synchronized (mToastQueue) {
1361 long callingId = Binder.clearCallingIdentity();
1362 try {
1363 int index = indexOfToastLocked(pkg, callback);
1364 if (index >= 0) {
1365 cancelToastLocked(index);
1366 } else {
1367 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1368 + " callback=" + callback);
1369 }
1370 } finally {
1371 Binder.restoreCallingIdentity(callingId);
1372 }
1373 }
1374 }
1375
1376 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001377 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Adam Lesinski182f73f2013-12-05 16:48:06 -08001378 Notification notification, int[] idOut, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001379 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Adam Lesinski182f73f2013-12-05 16:48:06 -08001380 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1381 }
1382
1383 @Override
1384 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001385 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001386 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1387 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04001388 // Don't allow client applications to cancel foreground service notis or autobundled
1389 // summaries.
John Spurlocke6a7d932014-03-13 12:29:00 -04001390 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Julia Reynoldse46bb372016-03-17 11:05:58 -04001391 (Binder.getCallingUid() == Process.SYSTEM_UID
1392 ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1393 | (Binder.getCallingUid() == Process.SYSTEM_UID
1394 ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
Chris Wren9fa689f2015-11-20 16:44:53 -05001395 REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001396 }
1397
1398 @Override
1399 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001400 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001401
1402 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1403 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1404
1405 // Calling from user space, don't allow the canceling of actively
1406 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04001407 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1408 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001409 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001410 }
1411
1412 @Override
1413 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
John Spurlock7340fc82014-04-24 18:50:12 -04001414 checkCallerIsSystem();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001415
1416 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
Chris Wrenacf424a2016-03-15 12:48:55 -04001417 mRankingHelper.setEnabled(pkg, uid, enabled);
1418 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001419 }
1420
1421 /**
1422 * Use this when you just want to know if notifications are OK for this package.
1423 */
1424 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001425 public boolean areNotificationsEnabled(String pkg) {
1426 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1427 }
1428
1429 /**
1430 * Use this when you just want to know if notifications are OK for this package.
1431 */
1432 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001433 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001434 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001435 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001436 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001437 }
1438
Chris Wren54bbef42014-07-09 18:37:56 -04001439 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001440 public void setPriority(String pkg, int uid, int priority) {
Julia Reynoldsdd3e86b2016-02-02 10:24:30 -05001441 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001442 mRankingHelper.setPriority(pkg, uid, priority);
Chris Wren54bbef42014-07-09 18:37:56 -04001443 savePolicyFile();
1444 }
1445
1446 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001447 public int getPriority(String pkg, int uid) {
Chris Wren54bbef42014-07-09 18:37:56 -04001448 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001449 return mRankingHelper.getPriority(pkg, uid);
Chris Wren54bbef42014-07-09 18:37:56 -04001450 }
1451
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001452 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001453 public void setVisibilityOverride(String pkg, int uid, int visibility) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001454 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001455 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001456 savePolicyFile();
1457 }
1458
1459 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001460 public int getVisibilityOverride(String pkg, int uid) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001461 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001462 return mRankingHelper.getVisibilityOverride(pkg, uid);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001463 }
1464
Julia Reynolds5d25ee72015-11-20 15:38:20 -05001465 @Override
Julia Reynolds0edb50c2016-02-26 14:08:25 -05001466 public void setImportance(String pkg, int uid, int importance) {
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001467 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynoldsef37f282016-02-12 09:11:27 -05001468 setNotificationsEnabledForPackageImpl(pkg, uid,
1469 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1470 mRankingHelper.setImportance(pkg, uid, importance);
Julia Reynolds5d25ee72015-11-20 15:38:20 -05001471 savePolicyFile();
1472 }
1473
1474 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001475 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001476 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05001477 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001478 }
1479
1480 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001481 public int getImportance(String pkg, int uid) {
Julia Reynoldscac88622016-03-03 09:28:19 -05001482 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynoldsef37f282016-02-12 09:11:27 -05001483 return mRankingHelper.getImportance(pkg, uid);
Julia Reynoldsbe8fdee2015-12-18 09:04:34 -05001484 }
1485
Adam Lesinski182f73f2013-12-05 16:48:06 -08001486 /**
1487 * System-only API for getting a list of current (i.e. not cleared) notifications.
1488 *
1489 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04001490 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001491 */
1492 @Override
1493 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1494 // enforce() will ensure the calling uid has the correct permission
1495 getContext().enforceCallingOrSelfPermission(
1496 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1497 "NotificationManagerService.getActiveNotifications");
1498
1499 StatusBarNotification[] tmp = null;
1500 int uid = Binder.getCallingUid();
1501
1502 // noteOp will check to make sure the callingPkg matches the uid
1503 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1504 == AppOpsManager.MODE_ALLOWED) {
1505 synchronized (mNotificationList) {
1506 tmp = new StatusBarNotification[mNotificationList.size()];
1507 final int N = mNotificationList.size();
1508 for (int i=0; i<N; i++) {
1509 tmp[i] = mNotificationList.get(i).sbn;
1510 }
1511 }
1512 }
1513 return tmp;
1514 }
1515
1516 /**
Dan Sandler994349c2015-04-15 11:02:54 -04001517 * Public API for getting a list of current notifications for the calling package/uid.
1518 *
1519 * @returns A list of all the package's notifications, in natural order.
1520 */
1521 @Override
1522 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1523 int incomingUserId) {
1524 checkCallerIsSystemOrSameApp(pkg);
1525 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1526 Binder.getCallingUid(), incomingUserId, true, false,
1527 "getAppActiveNotifications", pkg);
1528
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08001529 final ArrayList<StatusBarNotification> list
1530 = new ArrayList<StatusBarNotification>(mNotificationList.size());
Dan Sandler994349c2015-04-15 11:02:54 -04001531
1532 synchronized (mNotificationList) {
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08001533 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04001534 for (int i = 0; i < N; i++) {
1535 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04001536 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1537 && (sbn.getNotification().flags
Julia Reynolds4c4ad592016-04-12 11:16:37 -04001538 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
Dan Sandler994349c2015-04-15 11:02:54 -04001539 // We could pass back a cloneLight() but clients might get confused and
1540 // try to send this thing back to notify() again, which would not work
1541 // very well.
1542 final StatusBarNotification sbnOut = new StatusBarNotification(
1543 sbn.getPackageName(),
1544 sbn.getOpPkg(),
1545 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1546 0, // hide score from apps
1547 sbn.getNotification().clone(),
1548 sbn.getUser(), sbn.getPostTime());
1549 list.add(sbnOut);
1550 }
1551 }
1552 }
1553
1554 return new ParceledListSlice<StatusBarNotification>(list);
1555 }
1556
1557 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08001558 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1559 *
1560 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1561 */
1562 @Override
1563 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1564 // enforce() will ensure the calling uid has the correct permission
1565 getContext().enforceCallingOrSelfPermission(
1566 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1567 "NotificationManagerService.getHistoricalNotifications");
1568
1569 StatusBarNotification[] tmp = null;
1570 int uid = Binder.getCallingUid();
1571
1572 // noteOp will check to make sure the callingPkg matches the uid
1573 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1574 == AppOpsManager.MODE_ALLOWED) {
1575 synchronized (mArchive) {
1576 tmp = mArchive.getArray(count);
1577 }
1578 }
1579 return tmp;
1580 }
1581
1582 /**
1583 * Register a listener binder directly with the notification manager.
1584 *
1585 * Only works with system callers. Apps should extend
1586 * {@link android.service.notification.NotificationListenerService}.
1587 */
1588 @Override
1589 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05001590 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02001591 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05001592 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001593 }
1594
1595 /**
1596 * Remove a listener binder directly
1597 */
1598 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05001599 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05001600 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001601 }
1602
1603 /**
1604 * Allow an INotificationListener to simulate a "clear all" operation.
1605 *
1606 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1607 *
1608 * @param token The binder for the listener, to check that the caller is allowed
1609 */
1610 @Override
John Spurlocka4294292014-03-24 18:02:32 -04001611 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001612 final int callingUid = Binder.getCallingUid();
1613 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001614 long identity = Binder.clearCallingIdentity();
1615 try {
Adam Lesinskie8240262014-03-26 16:01:00 -07001616 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001617 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
John Spurlocka4294292014-03-24 18:02:32 -04001618 if (keys != null) {
1619 final int N = keys.length;
1620 for (int i = 0; i < N; i++) {
1621 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07001622 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00001623 final int userId = r.sbn.getUserId();
1624 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04001625 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00001626 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04001627 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00001628 }
Griff Hazen335e1f02014-09-11 14:49:31 -07001629 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1630 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1631 userId);
John Spurlocka4294292014-03-24 18:02:32 -04001632 }
1633 } else {
1634 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00001635 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04001636 }
Adam Lesinskie8240262014-03-26 16:01:00 -07001637 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001638 } finally {
1639 Binder.restoreCallingIdentity(identity);
1640 }
1641 }
1642
Chris Wrenab41eec2016-01-04 18:01:27 -05001643 /**
1644 * Handle request from an approved listener to re-enable itself.
1645 *
1646 * @param component The componenet to be re-enabled, caller must match package.
1647 */
1648 @Override
1649 public void requestBindListener(ComponentName component) {
1650 checkCallerIsSystemOrSameApp(component.getPackageName());
1651 long identity = Binder.clearCallingIdentity();
1652 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04001653 ManagedServices manager =
1654 mRankerServices.isComponentEnabledForCurrentProfiles(component)
Chris Wrene0ba7eb2016-03-04 17:30:43 -05001655 ? mRankerServices
Chris Wrenab41eec2016-01-04 18:01:27 -05001656 : mListeners;
1657 manager.setComponentState(component, true);
1658 } finally {
1659 Binder.restoreCallingIdentity(identity);
1660 }
1661 }
1662
1663 @Override
1664 public void requestUnbindListener(INotificationListener token) {
1665 long identity = Binder.clearCallingIdentity();
1666 try {
1667 // allow bound services to disable themselves
1668 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1669 info.getOwner().setComponentState(info.component, false);
1670 } finally {
1671 Binder.restoreCallingIdentity(identity);
1672 }
1673 }
1674
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001675 @Override
1676 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001677 long identity = Binder.clearCallingIdentity();
1678 try {
1679 synchronized (mNotificationList) {
1680 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1681 if (keys != null) {
1682 final int N = keys.length;
1683 for (int i = 0; i < N; i++) {
1684 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1685 if (r == null) continue;
1686 final int userId = r.sbn.getUserId();
1687 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1688 !mUserProfiles.isCurrentProfile(userId)) {
1689 throw new SecurityException("Disallowed call from listener: "
1690 + info.service);
1691 }
1692 if (!r.isSeen()) {
1693 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1694 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07001695 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001696 : userId,
Adam Lesinskic8e87292015-06-10 15:33:45 -07001697 UsageEvents.Event.USER_INTERACTION);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001698 r.setSeen();
1699 }
1700 }
1701 }
1702 }
1703 } finally {
1704 Binder.restoreCallingIdentity(identity);
1705 }
1706 }
1707
John Spurlock7340fc82014-04-24 18:50:12 -04001708 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00001709 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04001710 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1711 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1712 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00001713 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04001714 }
1715
Adam Lesinski182f73f2013-12-05 16:48:06 -08001716 /**
1717 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1718 *
1719 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1720 *
1721 * @param token The binder for the listener, to check that the caller is allowed
1722 */
1723 @Override
1724 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1725 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001726 final int callingUid = Binder.getCallingUid();
1727 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001728 long identity = Binder.clearCallingIdentity();
1729 try {
Adam Lesinskie8240262014-03-26 16:01:00 -07001730 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001731 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00001732 if (info.supportsProfiles()) {
1733 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1734 + "from " + info.component
1735 + " use cancelNotification(key) instead.");
1736 } else {
1737 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1738 pkg, tag, id, info.userid);
1739 }
Adam Lesinskie8240262014-03-26 16:01:00 -07001740 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001741 } finally {
1742 Binder.restoreCallingIdentity(identity);
1743 }
1744 }
1745
1746 /**
1747 * Allow an INotificationListener to request the list of outstanding notifications seen by
1748 * the current user. Useful when starting up, after which point the listener callbacks
1749 * should be used.
1750 *
1751 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001752 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04001753 * @returns The return value will contain the notifications specified in keys, in that
1754 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001755 */
1756 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02001757 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02001758 INotificationListener token, String[] keys, int trim) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001759 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001760 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001761 final boolean getKeys = keys != null;
1762 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02001763 final ArrayList<StatusBarNotification> list
1764 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02001765 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001766 final NotificationRecord r = getKeys
1767 ? mNotificationsByKey.get(keys[i])
1768 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02001769 if (r == null) continue;
1770 StatusBarNotification sbn = r.sbn;
1771 if (!isVisibleToListener(sbn, info)) continue;
1772 StatusBarNotification sbnToSend =
1773 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1774 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001775 }
Christoph Studercee44ba2014-05-20 18:36:43 +02001776 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001777 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001778 }
1779
1780 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04001781 public void requestHintsFromListener(INotificationListener token, int hints) {
1782 final long identity = Binder.clearCallingIdentity();
1783 try {
1784 synchronized (mNotificationList) {
1785 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07001786 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1787 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1788 | HINT_HOST_DISABLE_CALL_EFFECTS;
1789 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04001790 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07001791 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04001792 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07001793 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04001794 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001795 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04001796 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04001797 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001798 } finally {
1799 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04001800 }
1801 }
1802
1803 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04001804 public int getHintsFromListener(INotificationListener token) {
John Spurlock1fa865f2014-07-21 14:56:39 -04001805 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001806 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04001807 }
1808 }
1809
1810 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02001811 public void requestInterruptionFilterFromListener(INotificationListener token,
1812 int interruptionFilter) throws RemoteException {
1813 final long identity = Binder.clearCallingIdentity();
1814 try {
1815 synchronized (mNotificationList) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001816 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1817 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02001818 updateInterruptionFilterLocked();
1819 }
1820 } finally {
1821 Binder.restoreCallingIdentity(identity);
1822 }
1823 }
1824
1825 @Override
1826 public int getInterruptionFilterFromListener(INotificationListener token)
1827 throws RemoteException {
1828 synchronized (mNotificationLight) {
1829 return mInterruptionFilter;
1830 }
1831 }
1832
1833 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02001834 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1835 throws RemoteException {
1836 synchronized (mNotificationList) {
1837 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1838 if (info == null) return;
1839 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1840 }
1841 }
1842
1843 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04001844 public int getZenMode() {
1845 return mZenModeHelper.getZenMode();
1846 }
1847
1848 @Override
John Spurlock056c5192014-04-20 21:52:01 -04001849 public ZenModeConfig getZenModeConfig() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001850 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04001851 return mZenModeHelper.getConfig();
1852 }
1853
1854 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04001855 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001856 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1857 final long identity = Binder.clearCallingIdentity();
1858 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001859 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001860 } finally {
1861 Binder.restoreCallingIdentity(identity);
1862 }
1863 }
1864
1865 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05001866 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001867 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05001868 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001869 }
1870
1871 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001872 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1873 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001874 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001875 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001876 }
1877
1878 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05001879 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001880 throws RemoteException {
1881 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1882 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1883 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1884 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001885 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001886
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001887 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1888 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001889 }
1890
1891 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05001892 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001893 throws RemoteException {
1894 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1895 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1896 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1897 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1898 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001899
Julia Reynolds361e82d32016-02-26 18:19:49 -05001900 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001901 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001902 }
1903
1904 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001905 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1906 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001907 // Verify that they can modify zen rules.
1908 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1909
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001910 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001911 }
1912
1913 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05001914 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1915 Preconditions.checkNotNull(packageName, "Package name is null");
1916 enforceSystemOrSystemUI("removeAutomaticZenRules");
1917
1918 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1919 }
1920
1921 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05001922 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1923 Preconditions.checkNotNull(owner, "Owner is null");
1924 enforceSystemOrSystemUI("getRuleInstanceCount");
1925
1926 return mZenModeHelper.getCurrentInstanceCount(owner);
1927 }
1928
1929 @Override
John Spurlock80774932015-05-07 17:38:50 -04001930 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1931 enforcePolicyAccess(pkg, "setInterruptionFilter");
1932 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1933 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1934 final long identity = Binder.clearCallingIdentity();
1935 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001936 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04001937 } finally {
1938 Binder.restoreCallingIdentity(identity);
1939 }
1940 }
1941
1942 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04001943 public void notifyConditions(final String pkg, IConditionProvider provider,
1944 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04001945 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1946 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04001947 mHandler.post(new Runnable() {
1948 @Override
1949 public void run() {
1950 mConditionProviders.notifyConditions(pkg, info, conditions);
1951 }
1952 });
John Spurlocke77bb362014-04-26 10:24:59 -04001953 }
1954
John Spurlockcdb57ae2015-02-11 19:04:11 -05001955 private void enforceSystemOrSystemUIOrVolume(String message) {
1956 if (mAudioManagerInternal != null) {
1957 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1958 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1959 return;
1960 }
1961 }
1962 enforceSystemOrSystemUI(message);
1963 }
1964
John Spurlocke77bb362014-04-26 10:24:59 -04001965 private void enforceSystemOrSystemUI(String message) {
1966 if (isCallerSystem()) return;
1967 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1968 message);
John Spurlock7340fc82014-04-24 18:50:12 -04001969 }
1970
Julia Reynolds48034f82016-03-09 10:15:16 -05001971 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1972 try {
1973 checkCallerIsSystemOrSameApp(pkg);
1974 } catch (SecurityException e) {
1975 getContext().enforceCallingPermission(
1976 android.Manifest.permission.STATUS_BAR_SERVICE,
1977 message);
1978 }
1979 }
1980
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001981 private void enforcePolicyAccess(int uid, String method) {
1982 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1983 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1984 return;
1985 }
1986 boolean accessAllowed = false;
1987 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1988 final int packageCount = packages.length;
1989 for (int i = 0; i < packageCount; i++) {
1990 if (checkPolicyAccess(packages[i])) {
1991 accessAllowed = true;
1992 }
1993 }
1994 if (!accessAllowed) {
1995 Slog.w(TAG, "Notification policy access denied calling " + method);
1996 throw new SecurityException("Notification policy access denied");
1997 }
1998 }
1999
John Spurlock80774932015-05-07 17:38:50 -04002000 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04002001 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2002 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2003 return;
2004 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04002005 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002006 if (!checkPolicyAccess(pkg)) {
2007 Slog.w(TAG, "Notification policy access denied calling " + method);
2008 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04002009 }
2010 }
2011
John Spurlock80774932015-05-07 17:38:50 -04002012 private boolean checkPackagePolicyAccess(String pkg) {
John Spurlock7c74f782015-06-04 13:01:42 -04002013 return mPolicyAccess.isPackageGranted(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002014 }
2015
2016 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04002017 try {
2018 int uid = getContext().getPackageManager().getPackageUidAsUser(
2019 pkg, UserHandle.getCallingUserId());
2020 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2021 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2022 -1, true)) {
2023 return true;
2024 }
2025 } catch (NameNotFoundException e) {
2026 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002027 }
John Spurlock80774932015-05-07 17:38:50 -04002028 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002029 }
2030
John Spurlock7340fc82014-04-24 18:50:12 -04002031 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002032 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2033 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2034 != PackageManager.PERMISSION_GRANTED) {
John Spurlock2b122f42014-08-27 16:29:47 -04002035 pw.println("Permission Denial: can't dump NotificationManager from pid="
Adam Lesinski182f73f2013-12-05 16:48:06 -08002036 + Binder.getCallingPid()
2037 + ", uid=" + Binder.getCallingUid());
2038 return;
2039 }
2040
Chris Wrene4b38802015-07-07 15:54:19 -04002041 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2042 if (filter != null && filter.stats) {
2043 dumpJson(pw, filter);
2044 } else {
2045 dumpImpl(pw, filter);
2046 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002047 }
John Spurlockb4782522014-08-22 14:54:46 -04002048
2049 @Override
2050 public ComponentName getEffectsSuppressor() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002051 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
Bryce Leeba3d8952016-04-12 12:39:15 -07002052 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04002053 }
John Spurlock2b122f42014-08-27 16:29:47 -04002054
2055 @Override
2056 public boolean matchesCallFilter(Bundle extras) {
2057 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02002058 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002059 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02002060 extras,
2061 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2062 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2063 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04002064 }
John Spurlock530052a2014-11-30 16:26:19 -05002065
2066 @Override
2067 public boolean isSystemConditionProviderEnabled(String path) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002068 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04002069 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05002070 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002071
Christopher Tatef9767d62015-04-08 14:35:43 -07002072 // Backup/restore interface
2073 @Override
2074 public byte[] getBackupPayload(int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002075 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002076 //TODO: http://b/22388012
2077 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002078 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2079 return null;
2080 }
2081 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2082 try {
2083 writePolicyXml(baos, true /*forBackup*/);
2084 return baos.toByteArray();
2085 } catch (IOException e) {
2086 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2087 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002088 return null;
2089 }
2090
2091 @Override
2092 public void applyRestore(byte[] payload, int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002093 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2094 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2095 if (payload == null) {
2096 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2097 return;
2098 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002099 //TODO: http://b/22388012
2100 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002101 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2102 return;
2103 }
2104 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2105 try {
2106 readPolicyXml(bais, true /*forRestore*/);
2107 savePolicyFile();
2108 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2109 Slog.w(TAG, "applyRestore: error reading payload", e);
2110 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002111 }
2112
John Spurlock1fc476d2015-04-14 16:05:20 -04002113 @Override
John Spurlock80774932015-05-07 17:38:50 -04002114 public boolean isNotificationPolicyAccessGranted(String pkg) {
2115 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002116 }
2117
2118 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05002119 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2120 enforceSystemOrSystemUIOrSamePackage(pkg,
2121 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002122 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002123 }
2124
2125 @Override
2126 public String[] getPackagesRequestingNotificationPolicyAccess()
2127 throws RemoteException {
2128 enforceSystemOrSystemUI("request policy access packages");
2129 final long identity = Binder.clearCallingIdentity();
2130 try {
John Spurlock7c74f782015-06-04 13:01:42 -04002131 return mPolicyAccess.getRequestingPackages();
John Spurlock80774932015-05-07 17:38:50 -04002132 } finally {
2133 Binder.restoreCallingIdentity(identity);
2134 }
2135 }
2136
2137 @Override
2138 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2139 throws RemoteException {
2140 enforceSystemOrSystemUI("grant notification policy access");
2141 final long identity = Binder.clearCallingIdentity();
2142 try {
2143 synchronized (mNotificationList) {
2144 mPolicyAccess.put(pkg, granted);
2145 }
2146 } finally {
2147 Binder.restoreCallingIdentity(identity);
2148 }
2149 }
2150
2151 @Override
2152 public Policy getNotificationPolicy(String pkg) {
2153 enforcePolicyAccess(pkg, "getNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002154 final long identity = Binder.clearCallingIdentity();
2155 try {
2156 return mZenModeHelper.getNotificationPolicy();
2157 } finally {
2158 Binder.restoreCallingIdentity(identity);
2159 }
2160 }
2161
2162 @Override
John Spurlock80774932015-05-07 17:38:50 -04002163 public void setNotificationPolicy(String pkg, Policy policy) {
2164 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002165 final long identity = Binder.clearCallingIdentity();
2166 try {
2167 mZenModeHelper.setNotificationPolicy(policy);
2168 } finally {
2169 Binder.restoreCallingIdentity(identity);
2170 }
2171 }
Chris Wren51017d02015-12-15 15:34:46 -05002172
2173 @Override
Julia Reynoldse46bb372016-03-17 11:05:58 -04002174 public void applyAdjustmentFromRankerService(INotificationListener token,
2175 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05002176 final long identity = Binder.clearCallingIdentity();
2177 try {
2178 synchronized (mNotificationList) {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002179 mRankerServices.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002180 applyAdjustmentLocked(adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05002181 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002182 maybeAddAutobundleSummary(adjustment);
2183 mRankingHandler.requestSort();
2184 } finally {
2185 Binder.restoreCallingIdentity(identity);
2186 }
2187 }
2188
2189 @Override
2190 public void applyAdjustmentsFromRankerService(INotificationListener token,
2191 List<Adjustment> adjustments) throws RemoteException {
2192
2193 final long identity = Binder.clearCallingIdentity();
2194 try {
2195 synchronized (mNotificationList) {
2196 mRankerServices.checkServiceTokenLocked(token);
2197 for (Adjustment adjustment : adjustments) {
2198 applyAdjustmentLocked(adjustment);
2199 }
2200 }
2201 for (Adjustment adjustment : adjustments) {
2202 maybeAddAutobundleSummary(adjustment);
2203 }
2204 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05002205 } finally {
2206 Binder.restoreCallingIdentity(identity);
2207 }
2208 }
John Spurlock1fc476d2015-04-14 16:05:20 -04002209 };
John Spurlocka4294292014-03-24 18:02:32 -04002210
Julia Reynoldse46bb372016-03-17 11:05:58 -04002211 private void applyAdjustmentLocked(Adjustment adjustment) {
2212 maybeClearAutobundleSummaryLocked(adjustment);
2213 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2214 if (n == null) {
2215 return;
2216 }
2217 if (adjustment.getImportance() != IMPORTANCE_NONE) {
2218 n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2219 }
2220 if (adjustment.getSignals() != null) {
2221 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldsb1ebc3b2016-04-15 15:12:36 -04002222 final String autoGroupKey = adjustment.getSignals().getString(
2223 Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2224 if (autoGroupKey == null) {
2225 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2226 } else {
2227 EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2228 }
2229 n.sbn.setOverrideGroupKey(autoGroupKey);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002230 }
2231 }
2232
2233 // Clears the 'fake' auto-bunding summary.
2234 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002235 if (adjustment.getSignals() != null) {
2236 Bundle.setDefusable(adjustment.getSignals(), true);
2237 if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
Julia Reynoldse46bb372016-03-17 11:05:58 -04002238 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002239 ArrayMap<String, String> summaries =
2240 mAutobundledSummaries.get(adjustment.getUser());
2241 if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002242 // Clear summary.
2243 final NotificationRecord removed = mNotificationsByKey.get(
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002244 summaries.remove(adjustment.getPackage()));
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002245 if (removed != null) {
2246 mNotificationList.remove(removed);
2247 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2248 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002249 }
2250 }
2251 }
2252 }
2253
2254 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2255 private void maybeAddAutobundleSummary(Adjustment adjustment) {
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002256 if (adjustment.getSignals() != null) {
2257 Bundle.setDefusable(adjustment.getSignals(), true);
2258 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2259 final String newAutoBundleKey =
2260 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2261 int userId = -1;
2262 NotificationRecord summaryRecord = null;
2263 synchronized (mNotificationList) {
Selim Cinek5b03ce92016-05-18 15:16:58 -07002264 NotificationRecord notificationRecord =
2265 mNotificationsByKey.get(adjustment.getKey());
2266 if (notificationRecord == null) {
2267 // The notification could have been cancelled again already. A successive
2268 // adjustment will post a summary if needed.
2269 return;
2270 }
2271 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002272 userId = adjustedSbn.getUser().getIdentifier();
2273 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2274 if (summaries == null) {
2275 summaries = new ArrayMap<>();
2276 }
2277 mAutobundledSummaries.put(userId, summaries);
2278 if (!summaries.containsKey(adjustment.getPackage())
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002279 && newAutoBundleKey != null) {
2280 // Add summary
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002281 final ApplicationInfo appInfo =
2282 adjustedSbn.getNotification().extras.getParcelable(
2283 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2284 final Bundle extras = new Bundle();
2285 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2286 final Notification summaryNotification =
2287 new Notification.Builder(getContext()).setSmallIcon(
2288 adjustedSbn.getNotification().getSmallIcon())
2289 .setGroupSummary(true)
2290 .setGroup(newAutoBundleKey)
2291 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2292 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
Julia Reynolds3011fd42016-05-20 10:25:43 -04002293 .setColor(adjustedSbn.getNotification().color)
Julia Reynolds29607002016-07-06 10:45:05 -04002294 .setLocalOnly(true)
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002295 .build();
2296 summaryNotification.extras.putAll(extras);
Julia Reynolds5bba3e72016-04-15 15:13:54 -04002297 Intent appIntent = getContext().getPackageManager()
2298 .getLaunchIntentForPackage(adjustment.getPackage());
2299 if (appIntent != null) {
2300 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2301 getContext(), 0, appIntent, 0, null,
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002302 UserHandle.of(userId));
Julia Reynolds5bba3e72016-04-15 15:13:54 -04002303 }
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002304 final StatusBarNotification summarySbn =
2305 new StatusBarNotification(adjustedSbn.getPackageName(),
2306 adjustedSbn.getOpPkg(),
2307 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2308 adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2309 summaryNotification, adjustedSbn.getUser(),
2310 newAutoBundleKey,
2311 System.currentTimeMillis());
2312 summaryRecord = new NotificationRecord(getContext(), summarySbn);
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002313 summaries.put(adjustment.getPackage(), summarySbn.getKey());
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002314 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002315 }
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002316 if (summaryRecord != null) {
2317 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2318 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002319 }
2320 }
2321 }
2322
John Spurlock32fe4c62014-10-02 12:16:02 -04002323 private String disableNotificationEffects(NotificationRecord record) {
2324 if (mDisableNotificationEffects) {
2325 return "booleanState";
2326 }
2327 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2328 return "listenerHints";
2329 }
2330 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2331 return "callState";
2332 }
2333 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04002334 };
2335
2336 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2337 JSONObject dump = new JSONObject();
2338 try {
2339 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04002340 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2341 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04002342 dump.put("stats", mUsageStats.dumpJson(filter));
2343 } catch (JSONException e) {
2344 e.printStackTrace();
2345 }
2346 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04002347 }
2348
John Spurlock25e2d242014-06-27 13:58:23 -04002349 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2350 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04002351 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04002352 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04002353 }
2354 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08002355 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002356 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002357
John Spurlock50806fc2014-07-15 10:22:02 -04002358 if (!zenOnly) {
2359 synchronized (mToastQueue) {
2360 N = mToastQueue.size();
2361 if (N > 0) {
2362 pw.println(" Toast Queue:");
2363 for (int i=0; i<N; i++) {
2364 mToastQueue.get(i).dump(pw, " ", filter);
2365 }
2366 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002367 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002368 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002369 }
2370
2371 synchronized (mNotificationList) {
John Spurlock50806fc2014-07-15 10:22:02 -04002372 if (!zenOnly) {
2373 N = mNotificationList.size();
John Spurlock25e2d242014-06-27 13:58:23 -04002374 if (N > 0) {
John Spurlock50806fc2014-07-15 10:22:02 -04002375 pw.println(" Notification List:");
John Spurlock25e2d242014-06-27 13:58:23 -04002376 for (int i=0; i<N; i++) {
John Spurlock50806fc2014-07-15 10:22:02 -04002377 final NotificationRecord nr = mNotificationList.get(i);
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002378 if (filter.filtered && !filter.matches(nr.sbn)) continue;
Dan Sandlera1770312015-07-10 13:59:29 -04002379 nr.dump(pw, " ", getContext(), filter.redact);
John Spurlock25e2d242014-06-27 13:58:23 -04002380 }
2381 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002382 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002383
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002384 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04002385 N = mLights.size();
2386 if (N > 0) {
2387 pw.println(" Lights List:");
2388 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05002389 if (i == N - 1) {
2390 pw.print(" > ");
2391 } else {
2392 pw.print(" ");
2393 }
2394 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04002395 }
2396 pw.println(" ");
2397 }
John Spurlockcb566aa2014-08-03 22:58:28 -04002398 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2399 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05002400 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2401 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002402 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04002403 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04002404 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04002405 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04002406 }
2407 pw.println(" mArchive=" + mArchive.toString());
2408 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2409 int i=0;
2410 while (iter.hasNext()) {
2411 final StatusBarNotification sbn = iter.next();
2412 if (filter != null && !filter.matches(sbn)) continue;
2413 pw.println(" " + sbn);
2414 if (++i >= 5) {
2415 if (iter.hasNext()) pw.println(" ...");
2416 break;
2417 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002418 }
2419 }
2420
John Spurlock50806fc2014-07-15 10:22:02 -04002421 if (!zenOnly) {
2422 pw.println("\n Usage Stats:");
2423 mUsageStats.dump(pw, " ", filter);
2424 }
Christoph Studer546bec82014-03-14 12:17:12 +01002425
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002426 if (!filter.filtered || zenOnly) {
John Spurlock25e2d242014-06-27 13:58:23 -04002427 pw.println("\n Zen Mode:");
John Spurlockf3701772015-02-12 13:29:37 -05002428 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
John Spurlock25e2d242014-06-27 13:58:23 -04002429 mZenModeHelper.dump(pw, " ");
John Spurlock6ae82a72014-07-16 16:23:01 -04002430
2431 pw.println("\n Zen Log:");
2432 ZenLog.dump(pw, " ");
John Spurlock25e2d242014-06-27 13:58:23 -04002433 }
John Spurlocke77bb362014-04-26 10:24:59 -04002434
John Spurlock50806fc2014-07-15 10:22:02 -04002435 if (!zenOnly) {
2436 pw.println("\n Ranking Config:");
2437 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04002438
John Spurlock50806fc2014-07-15 10:22:02 -04002439 pw.println("\n Notification listeners:");
2440 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002441 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2442 pw.print(" mListenersDisablingEffects: (");
2443 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04002444 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002445 final int hint = mListenersDisablingEffects.keyAt(i);
2446 if (i > 0) pw.print(';');
2447 pw.print("hint[" + hint + "]:");
2448
2449 final ArraySet<ManagedServiceInfo> listeners =
2450 mListenersDisablingEffects.valueAt(i);
2451 final int listenerSize = listeners.size();
2452
2453 for (int j = 0; j < listenerSize; j++) {
2454 if (i > 0) pw.print(',');
2455 final ManagedServiceInfo listener = listeners.valueAt(i);
2456 pw.print(listener.component);
2457 }
John Spurlock1fa865f2014-07-21 14:56:39 -04002458 }
2459 pw.println(')');
Chris Wren0efdb882016-03-01 17:17:47 -05002460 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002461 pw.println("\n Notification ranker services:");
2462 mRankerServices.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04002463 }
John Spurlock80774932015-05-07 17:38:50 -04002464 pw.println("\n Policy access:");
2465 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
John Spurlocke77bb362014-04-26 10:24:59 -04002466
2467 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04002468 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02002469
2470 pw.println("\n Group summaries:");
2471 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2472 NotificationRecord r = entry.getValue();
2473 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2474 if (mNotificationsByKey.get(r.getKey()) != r) {
2475 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04002476 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02002477 }
2478 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002479 }
2480 }
2481
Adam Lesinski182f73f2013-12-05 16:48:06 -08002482 /**
2483 * The private API only accessible to the system process.
2484 */
2485 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2486 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002487 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002488 String tag, int id, Notification notification, int[] idReceived, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002489 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002490 idReceived, userId);
2491 }
Christoph Studer365e4c32014-09-18 20:35:36 +02002492
2493 @Override
2494 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2495 int userId) {
2496 checkCallerIsSystem();
2497 synchronized (mNotificationList) {
2498 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2499 if (i < 0) {
2500 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2501 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2502 return;
2503 }
2504 NotificationRecord r = mNotificationList.get(i);
2505 StatusBarNotification sbn = r.sbn;
2506 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2507 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2508 // we have to revert to the flags we received initially *and* force remove
2509 // FLAG_FOREGROUND_SERVICE.
2510 sbn.getNotification().flags =
2511 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2512 mRankingHelper.sort(mNotificationList);
2513 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2514 }
2515 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002516 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002517
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002518 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04002519 final int callingPid, final String tag, final int id, final Notification notification,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002520 int[] idOut, int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04002521 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002522 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2523 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04002524 }
John Spurlock7340fc82014-04-24 18:50:12 -04002525 checkCallerIsSystemOrSameApp(pkg);
2526 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
Justin Koh38156c52014-06-04 13:57:49 -07002527 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002528
Scott Greenwald9b05c612013-06-25 23:44:05 -04002529 final int userId = ActivityManager.handleIncomingUser(callingPid,
2530 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07002531 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07002532
Julia Reynoldse46bb372016-03-17 11:05:58 -04002533 // Fix the notification as best we can.
2534 try {
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06002535 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2536 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2537 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2538 Notification.addFieldsFromContext(ai, userId, notification);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002539 } catch (NameNotFoundException e) {
2540 Slog.e(TAG, "Cannot create a context for sending app", e);
2541 return;
2542 }
2543
Chris Wren888b7a82016-06-17 15:47:19 -04002544 mUsageStats.registerEnqueuedByApp(pkg);
2545
Chris Wrena61f1792016-08-04 11:24:42 -04002546
2547 if (pkg == null || notification == null) {
2548 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2549 + " id=" + id + " notification=" + notification);
2550 }
2551 final StatusBarNotification n = new StatusBarNotification(
2552 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2553 user);
2554
Joe Onoratobd73d012010-06-04 11:44:54 -07002555 // Limit the number of notifications that any given package except the android
Justin Koh38156c52014-06-04 13:57:49 -07002556 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2557 if (!isSystemNotification && !isNotificationFromListener) {
Joe Onoratobd73d012010-06-04 11:44:54 -07002558 synchronized (mNotificationList) {
Chris Wrena61f1792016-08-04 11:24:42 -04002559 if(mNotificationsByKey.get(n.getKey()) != null) {
2560 // this is an update, rate limit updates only
2561 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
2562 if (appEnqueueRate > mMaxPackageEnqueueRate) {
2563 mUsageStats.registerOverRateQuota(pkg);
2564 final long now = SystemClock.elapsedRealtime();
2565 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2566 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2567 + ". Shedding events. package=" + pkg);
2568 mLastOverRateLogTime = now;
2569 }
2570 return;
Chris Wrenc8673a82016-05-17 17:11:29 -04002571 }
Chris Wrenc8673a82016-05-17 17:11:29 -04002572 }
2573
Joe Onoratobd73d012010-06-04 11:44:54 -07002574 int count = 0;
2575 final int N = mNotificationList.size();
2576 for (int i=0; i<N; i++) {
2577 final NotificationRecord r = mNotificationList.get(i);
Daniel Sandler4f91efd2013-04-25 16:38:41 -04002578 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
Vladimir Marko2526f332013-09-11 11:13:55 +01002579 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2580 break; // Allow updating existing notification
2581 }
Joe Onoratobd73d012010-06-04 11:44:54 -07002582 count++;
2583 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
Chris Wrenc8673a82016-05-17 17:11:29 -04002584 mUsageStats.registerOverCountQuota(pkg);
Joe Onoratobd73d012010-06-04 11:44:54 -07002585 Slog.e(TAG, "Package has already posted " + count
2586 + " notifications. Not showing more. package=" + pkg);
2587 return;
2588 }
2589 }
2590 }
2591 }
2592 }
2593
Felipe Lemedd85da62016-06-28 11:29:54 -07002594 // Whitelist pending intents.
2595 if (notification.allPendingIntents != null) {
2596 final int intentCount = notification.allPendingIntents.size();
2597 if (intentCount > 0) {
2598 final ActivityManagerInternal am = LocalServices
2599 .getService(ActivityManagerInternal.class);
2600 final long duration = LocalServices.getService(
2601 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
2602 for (int i = 0; i < intentCount; i++) {
2603 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
2604 if (pendingIntent != null) {
2605 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
2606 }
2607 }
2608 }
2609 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07002610
Chris Wren47633422016-01-22 09:56:59 -05002611 // Sanitize inputs
2612 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2613 Notification.PRIORITY_MAX);
Daniel Sandler0da673f2012-04-11 12:33:16 -04002614
Chris Wren47633422016-01-22 09:56:59 -05002615 // setup local book-keeping
Chris Wren47633422016-01-22 09:56:59 -05002616 final NotificationRecord r = new NotificationRecord(getContext(), n);
2617 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002618
2619 idOut[0] = id;
2620 }
2621
Chris Wren47633422016-01-22 09:56:59 -05002622 private class EnqueueNotificationRunnable implements Runnable {
2623 private final NotificationRecord r;
2624 private final int userId;
2625
2626 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2627 this.userId = userId;
2628 this.r = r;
2629 };
2630
2631 @Override
2632 public void run() {
2633
2634 synchronized (mNotificationList) {
2635 final StatusBarNotification n = r.sbn;
Chris Wren1ac52a92016-02-24 14:54:52 -05002636 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
Chris Wren47633422016-01-22 09:56:59 -05002637 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2638 if (old != null) {
2639 // Retain ranking information from previous record
2640 r.copyRankingInformation(old);
2641 }
2642
2643 final int callingUid = n.getUid();
2644 final int callingPid = n.getInitialPid();
2645 final Notification notification = n.getNotification();
2646 final String pkg = n.getPackageName();
2647 final int id = n.getId();
2648 final String tag = n.getTag();
2649 final boolean isSystemNotification = isUidSystem(callingUid) ||
2650 ("android".equals(pkg));
2651
2652 // Handle grouped notifications and bail out early if we
2653 // can to avoid extracting signals.
2654 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
Chris Wren47633422016-01-22 09:56:59 -05002655
2656 // This conditional is a dirty hack to limit the logging done on
2657 // behalf of the download manager without affecting other apps.
2658 if (!pkg.equals("com.android.providers.downloads")
2659 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2660 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren8ab776c2016-04-11 16:48:24 -04002661 if (old != null) {
Chris Wren47633422016-01-22 09:56:59 -05002662 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2663 }
2664 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2665 pkg, id, tag, userId, notification.toString(),
2666 enqueueStatus);
2667 }
2668
Chris Wren47633422016-01-22 09:56:59 -05002669 mRankingHelper.extractSignals(r);
2670
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002671 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
Chris Wren47633422016-01-22 09:56:59 -05002672
Julia Reynoldsef37f282016-02-12 09:11:27 -05002673 // blocked apps
Chris Wren47633422016-01-22 09:56:59 -05002674 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002675 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
Chris Wren47633422016-01-22 09:56:59 -05002676 if (!isSystemNotification) {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002677 if (isPackageSuspended) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00002678 Slog.e(TAG, "Suppressing notification from package due to package "
2679 + "suspended by administrator.");
2680 mUsageStats.registerSuspendedByAdmin(r);
2681 } else {
2682 Slog.e(TAG, "Suppressing notification from package by user request.");
2683 mUsageStats.registerBlocked(r);
2684 }
Chris Wren47633422016-01-22 09:56:59 -05002685 return;
2686 }
2687 }
2688
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002689 // tell the ranker service about the notification
2690 if (mRankerServices.isEnabled()) {
2691 mRankerServices.onNotificationEnqueued(r);
Chris Wren47633422016-01-22 09:56:59 -05002692 // TODO delay the code below here for 100ms or until there is an answer
2693 }
2694
2695
2696 int index = indexOfNotificationLocked(n.getKey());
2697 if (index < 0) {
2698 mNotificationList.add(r);
2699 mUsageStats.registerPostedByApp(r);
2700 } else {
2701 old = mNotificationList.get(index);
2702 mNotificationList.set(index, r);
2703 mUsageStats.registerUpdatedByApp(r, old);
2704 // Make sure we don't lose the foreground service state.
2705 notification.flags |=
2706 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2707 r.isUpdate = true;
2708 }
2709
2710 mNotificationsByKey.put(n.getKey(), r);
2711
2712 // Ensure if this is a foreground service that the proper additional
2713 // flags are set.
2714 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2715 notification.flags |= Notification.FLAG_ONGOING_EVENT
2716 | Notification.FLAG_NO_CLEAR;
2717 }
2718
2719 applyZenModeLocked(r);
2720 mRankingHelper.sort(mNotificationList);
2721
2722 if (notification.getSmallIcon() != null) {
2723 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2724 mListeners.notifyPostedLocked(n, oldSbn);
2725 } else {
2726 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2727 if (old != null && !old.isCanceled) {
2728 mListeners.notifyRemovedLocked(n);
2729 }
2730 // ATTENTION: in a future release we will bail out here
2731 // so that we do not play sounds, show lights, etc. for invalid
2732 // notifications
2733 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2734 + n.getPackageName());
2735 }
2736
2737 buzzBeepBlinkLocked(r);
2738 }
2739 }
2740 }
2741
Christoph Studer265c1052014-07-23 17:14:33 +02002742 /**
2743 * Ensures that grouped notification receive their special treatment.
2744 *
2745 * <p>Cancels group children if the new notification causes a group to lose
2746 * its summary.</p>
2747 *
2748 * <p>Updates mSummaryByGroupKey.</p>
2749 */
2750 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2751 int callingUid, int callingPid) {
2752 StatusBarNotification sbn = r.sbn;
2753 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07002754 if (n.isGroupSummary() && !sbn.isAppGroup()) {
2755 // notifications without a group shouldn't be a summary, otherwise autobundling can
2756 // lead to bugs
2757 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2758 }
2759
Christoph Studer265c1052014-07-23 17:14:33 +02002760 String group = sbn.getGroupKey();
2761 boolean isSummary = n.isGroupSummary();
2762
2763 Notification oldN = old != null ? old.sbn.getNotification() : null;
2764 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2765 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2766
2767 if (oldIsSummary) {
2768 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2769 if (removedSummary != old) {
2770 String removedKey =
2771 removedSummary != null ? removedSummary.getKey() : "<null>";
2772 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2773 ", removed=" + removedKey);
2774 }
2775 }
2776 if (isSummary) {
2777 mSummaryByGroupKey.put(group, r);
2778 }
2779
2780 // Clear out group children of the old notification if the update
2781 // causes the group summary to go away. This happens when the old
2782 // notification was a summary and the new one isn't, or when the old
2783 // notification was a summary and its group key changed.
2784 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2785 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
Selim Cinekce87a8a2016-06-20 15:40:07 -07002786 REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
Christoph Studer265c1052014-07-23 17:14:33 +02002787 }
2788 }
2789
Chris Wren93bb8b82016-03-29 14:35:05 -04002790 @VisibleForTesting
2791 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04002792 boolean buzz = false;
2793 boolean beep = false;
2794 boolean blink = false;
2795
Chris Wrena3446562014-06-03 18:11:47 -04002796 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04002797 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04002798
2799 // Should this notification make noise, vibe, or use the LED?
Julia Reynoldsf0f629f2016-02-25 09:34:04 -05002800 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
Chris Wrence00a232014-11-21 16:25:19 -05002801 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
Chris Wrena3446562014-06-03 18:11:47 -04002802 if (DBG || record.isIntercepted())
2803 Slog.v(TAG,
2804 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2805 " intercept=" + record.isIntercepted()
2806 );
2807
2808 final int currentUser;
2809 final long token = Binder.clearCallingIdentity();
2810 try {
2811 currentUser = ActivityManager.getCurrentUser();
2812 } finally {
2813 Binder.restoreCallingIdentity(token);
2814 }
2815
2816 // If we're not supposed to beep, vibrate, etc. then don't.
John Spurlock32fe4c62014-10-02 12:16:02 -04002817 final String disableEffects = disableNotificationEffects(record);
2818 if (disableEffects != null) {
2819 ZenLog.traceDisableEffects(record, disableEffects);
2820 }
Chris Wren93bb8b82016-03-29 14:35:05 -04002821
2822 // Remember if this notification already owns the notification channels.
2823 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2824 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2825
2826 // These are set inside the conditional if the notification is allowed to make noise.
2827 boolean hasValidVibrate = false;
2828 boolean hasValidSound = false;
John Spurlock32fe4c62014-10-02 12:16:02 -04002829 if (disableEffects == null
Chris Wrena3446562014-06-03 18:11:47 -04002830 && (record.getUserId() == UserHandle.USER_ALL ||
2831 record.getUserId() == currentUser ||
2832 mUserProfiles.isCurrentProfile(record.getUserId()))
2833 && canInterrupt
2834 && mSystemReady
2835 && mAudioManager != null) {
2836 if (DBG) Slog.v(TAG, "Interrupting!");
2837
Chris Wrena3446562014-06-03 18:11:47 -04002838 // should we use the default notification sound? (indicated either by
2839 // DEFAULT_SOUND or because notification.sound is pointing at
2840 // Settings.System.NOTIFICATION_SOUND)
2841 final boolean useDefaultSound =
2842 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2843 Settings.System.DEFAULT_NOTIFICATION_URI
2844 .equals(notification.sound);
2845
2846 Uri soundUri = null;
Chris Wrena3446562014-06-03 18:11:47 -04002847 if (useDefaultSound) {
2848 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2849
2850 // check to see if the default notification sound is silent
Chris Wrend4054312016-06-24 17:07:40 -04002851 hasValidSound = mSystemNotificationSound != null;
Chris Wrena3446562014-06-03 18:11:47 -04002852 } else if (notification.sound != null) {
2853 soundUri = notification.sound;
2854 hasValidSound = (soundUri != null);
2855 }
2856
Chris Wrena3446562014-06-03 18:11:47 -04002857 // Does the notification want to specify its own vibration?
2858 final boolean hasCustomVibrate = notification.vibrate != null;
2859
2860 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2861 // mode, and no other vibration is specified, we fall back to vibration
2862 final boolean convertSoundToVibration =
Chris Wren93bb8b82016-03-29 14:35:05 -04002863 !hasCustomVibrate
2864 && hasValidSound
2865 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
Chris Wrena3446562014-06-03 18:11:47 -04002866
2867 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2868 final boolean useDefaultVibrate =
2869 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2870
Chris Wren93bb8b82016-03-29 14:35:05 -04002871 hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2872 hasCustomVibrate;
Chris Wrena3446562014-06-03 18:11:47 -04002873
Chris Wren93bb8b82016-03-29 14:35:05 -04002874 // We can alert, and we're allowed to alert, but if the developer asked us to only do
2875 // it once, and we already have, then don't.
2876 if (!(record.isUpdate
2877 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2878
2879 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2880
2881 if (hasValidSound) {
2882 boolean looping =
2883 (notification.flags & Notification.FLAG_INSISTENT) != 0;
2884 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2885 mSoundNotificationKey = key;
2886 // do not play notifications if stream volume is 0 (typically because
2887 // ringer mode is silent) or if there is a user of exclusive audio focus
2888 if ((mAudioManager.getStreamVolume(
2889 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2890 && !mAudioManager.isAudioFocusExclusive()) {
2891 final long identity = Binder.clearCallingIdentity();
2892 try {
2893 final IRingtonePlayer player =
2894 mAudioManager.getRingtonePlayer();
2895 if (player != null) {
2896 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2897 + " with attributes " + audioAttributes);
2898 player.playAsync(soundUri, record.sbn.getUser(), looping,
2899 audioAttributes);
2900 beep = true;
2901 }
2902 } catch (RemoteException e) {
2903 } finally {
2904 Binder.restoreCallingIdentity(identity);
2905 }
Chris Wrena3446562014-06-03 18:11:47 -04002906 }
Chris Wren93bb8b82016-03-29 14:35:05 -04002907 }
2908
2909 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2910 == AudioManager.RINGER_MODE_SILENT)) {
2911 mVibrateNotificationKey = key;
2912
2913 if (useDefaultVibrate || convertSoundToVibration) {
2914 // Escalate privileges so we can use the vibrator even if the
2915 // notifying app does not have the VIBRATE permission.
2916 long identity = Binder.clearCallingIdentity();
2917 try {
2918 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2919 useDefaultVibrate ? mDefaultVibrationPattern
2920 : mFallbackVibrationPattern,
2921 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2922 ? 0: -1, audioAttributesForNotification(notification));
2923 buzz = true;
2924 } finally {
2925 Binder.restoreCallingIdentity(identity);
2926 }
2927 } else if (notification.vibrate.length > 1) {
2928 // If you want your own vibration pattern, you need the VIBRATE
2929 // permission
2930 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2931 notification.vibrate,
2932 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2933 ? 0: -1, audioAttributesForNotification(notification));
2934 buzz = true;
2935 }
Chris Wrena3446562014-06-03 18:11:47 -04002936 }
2937 }
Chris Wren93bb8b82016-03-29 14:35:05 -04002938
2939 }
2940 // If a notification is updated to remove the actively playing sound or vibrate,
2941 // cancel that feedback now
2942 if (wasBeep && !hasValidSound) {
2943 clearSoundLocked();
2944 }
2945 if (wasBuzz && !hasValidVibrate) {
2946 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04002947 }
2948
2949 // light
2950 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04002951 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002952 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2953 && ((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05002954 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04002955 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04002956 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04002957 if (mUseAttentionLight) {
2958 mAttentionLight.pulse();
2959 }
Chris Wren82ba59d2015-06-05 11:23:44 -04002960 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04002961 } else if (wasShowLights) {
2962 updateLightsLocked();
2963 }
Chris Wren82ba59d2015-06-05 11:23:44 -04002964 if (buzz || beep || blink) {
Julia Reynolds61721582016-01-05 08:35:25 -05002965 if (((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05002966 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
Julia Reynolds61721582016-01-05 08:35:25 -05002967 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2968 } else {
Chris Wren93bb8b82016-03-29 14:35:05 -04002969 EventLogTags.writeNotificationAlert(key,
Julia Reynolds61721582016-01-05 08:35:25 -05002970 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2971 mHandler.post(mBuzzBeepBlinked);
2972 }
John Spurlockcad57682014-07-26 17:09:56 -04002973 }
Chris Wrena3446562014-06-03 18:11:47 -04002974 }
2975
John Spurlock7b414672014-07-18 13:02:39 -04002976 private static AudioAttributes audioAttributesForNotification(Notification n) {
Marco Nelissen1c066302014-11-18 10:48:12 -08002977 if (n.audioAttributes != null
2978 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2979 // the audio attributes are set and different from the default, use them
John Spurlockbfa5dc42014-07-28 23:30:45 -04002980 return n.audioAttributes;
Jean-Michel Triviceb79bc2014-09-05 11:09:14 -07002981 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2982 // the stream type is valid, use it
2983 return new AudioAttributes.Builder()
2984 .setInternalLegacyStreamType(n.audioStreamType)
2985 .build();
2986 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2987 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2988 } else {
2989 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2990 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
John Spurlockbfa5dc42014-07-28 23:30:45 -04002991 }
John Spurlock7b414672014-07-18 13:02:39 -04002992 }
2993
Adam Lesinski182f73f2013-12-05 16:48:06 -08002994 void showNextToastLocked() {
2995 ToastRecord record = mToastQueue.get(0);
2996 while (record != null) {
2997 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2998 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002999 record.callback.show(record.token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003000 scheduleTimeoutLocked(record);
3001 return;
3002 } catch (RemoteException e) {
3003 Slog.w(TAG, "Object died trying to show notification " + record.callback
3004 + " in package " + record.pkg);
3005 // remove it from the list and let the process die
3006 int index = mToastQueue.indexOf(record);
3007 if (index >= 0) {
3008 mToastQueue.remove(index);
3009 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07003010 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003011 if (mToastQueue.size() > 0) {
3012 record = mToastQueue.get(0);
3013 } else {
3014 record = null;
3015 }
3016 }
3017 }
3018 }
3019
3020 void cancelToastLocked(int index) {
3021 ToastRecord record = mToastQueue.get(index);
3022 try {
3023 record.callback.hide();
3024 } catch (RemoteException e) {
3025 Slog.w(TAG, "Object died trying to hide notification " + record.callback
3026 + " in package " + record.pkg);
3027 // don't worry about this, we're about to remove it from
3028 // the list anyway
3029 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07003030
3031 ToastRecord lastToast = mToastQueue.remove(index);
3032 mWindowManagerInternal.removeWindowToken(lastToast.token, true);
3033
3034 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003035 if (mToastQueue.size() > 0) {
3036 // Show the next one. If the callback fails, this will remove
3037 // it from the list, so don't assume that the list hasn't changed
3038 // after this point.
3039 showNextToastLocked();
3040 }
3041 }
3042
3043 private void scheduleTimeoutLocked(ToastRecord r)
3044 {
3045 mHandler.removeCallbacksAndMessages(r);
3046 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3047 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3048 mHandler.sendMessageDelayed(m, delay);
3049 }
3050
3051 private void handleTimeout(ToastRecord record)
3052 {
3053 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3054 synchronized (mToastQueue) {
3055 int index = indexOfToastLocked(record.pkg, record.callback);
3056 if (index >= 0) {
3057 cancelToastLocked(index);
3058 }
3059 }
3060 }
3061
3062 // lock on mToastQueue
3063 int indexOfToastLocked(String pkg, ITransientNotification callback)
3064 {
3065 IBinder cbak = callback.asBinder();
3066 ArrayList<ToastRecord> list = mToastQueue;
3067 int len = list.size();
3068 for (int i=0; i<len; i++) {
3069 ToastRecord r = list.get(i);
3070 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3071 return i;
3072 }
3073 }
3074 return -1;
3075 }
3076
3077 // lock on mToastQueue
Svetoslav Ganovaa076532016-08-01 19:16:43 -07003078 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08003079 {
3080 int toastCount = 0; // toasts from this pid
3081 ArrayList<ToastRecord> list = mToastQueue;
3082 int N = list.size();
3083 for (int i=0; i<N; i++) {
3084 ToastRecord r = list.get(i);
3085 if (r.pid == pid) {
3086 toastCount++;
3087 }
3088 }
3089 try {
3090 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3091 } catch (RemoteException e) {
3092 // Shouldn't happen.
3093 }
3094 }
3095
Chris Wrenf9536642014-04-17 10:01:54 -04003096 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04003097 if (!(message.obj instanceof RankingReconsideration)) return;
3098 RankingReconsideration recon = (RankingReconsideration) message.obj;
3099 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04003100 boolean changed;
Chris Wren470c1ac2014-05-21 15:28:10 -04003101 synchronized (mNotificationList) {
3102 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3103 if (record == null) {
3104 return;
Chris Wrenf9536642014-04-17 10:01:54 -04003105 }
Chris Wren333a61c2014-05-28 16:40:57 -04003106 int indexBefore = findNotificationRecordIndexLocked(record);
3107 boolean interceptBefore = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003108 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04003109 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04003110 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04003111 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04003112 int indexAfter = findNotificationRecordIndexLocked(record);
3113 boolean interceptAfter = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003114 int visibilityAfter = record.getPackageVisibilityOverride();
3115 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3116 || visibilityBefore != visibilityAfter;
Chris Wrena3446562014-06-03 18:11:47 -04003117 if (interceptBefore && !interceptAfter) {
3118 buzzBeepBlinkLocked(record);
3119 }
Chris Wrenf9536642014-04-17 10:01:54 -04003120 }
Chris Wren333a61c2014-05-28 16:40:57 -04003121 if (changed) {
Chris Wren470c1ac2014-05-21 15:28:10 -04003122 scheduleSendRankingUpdate();
3123 }
3124 }
3125
Chris Wren51017d02015-12-15 15:34:46 -05003126 private void handleRankingSort() {
Chris Wren54bbef42014-07-09 18:37:56 -04003127 synchronized (mNotificationList) {
3128 final int N = mNotificationList.size();
3129 ArrayList<String> orderBefore = new ArrayList<String>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003130 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003131 int[] visibilities = new int[N];
Julia Reynoldse46bb372016-03-17 11:05:58 -04003132 int[] importances = new int[N];
Chris Wren54bbef42014-07-09 18:37:56 -04003133 for (int i = 0; i < N; i++) {
3134 final NotificationRecord r = mNotificationList.get(i);
3135 orderBefore.add(r.getKey());
Julia Reynoldse46bb372016-03-17 11:05:58 -04003136 groupOverrideBefore.add(r.sbn.getGroupKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003137 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds69766692016-02-01 15:35:08 -05003138 importances[i] = r.getImportance();
Chris Wren54bbef42014-07-09 18:37:56 -04003139 mRankingHelper.extractSignals(r);
3140 }
Chris Wren19a02b02015-12-22 10:34:22 -05003141 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04003142 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003143 final NotificationRecord r = mNotificationList.get(i);
3144 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05003145 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldse46bb372016-03-17 11:05:58 -04003146 || importances[i] != r.getImportance()
3147 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
Chris Wren54bbef42014-07-09 18:37:56 -04003148 scheduleSendRankingUpdate();
3149 return;
3150 }
3151 }
3152 }
3153 }
3154
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04003155 private void recordCallerLocked(NotificationRecord record) {
3156 if (mZenModeHelper.isCall(record)) {
3157 mZenModeHelper.recordCaller(record);
3158 }
3159 }
3160
Christoph Studerd5092bc2014-07-03 17:47:58 +02003161 // let zen mode evaluate this record
Chris Wren333a61c2014-05-28 16:40:57 -04003162 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02003163 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003164 if (record.isIntercepted()) {
Julia Reynoldsd5607292016-02-05 15:25:58 -05003165 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3166 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3167 | (mZenModeHelper.shouldSuppressWhenScreenOn()
3168 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003169 record.setSuppressedVisualEffects(suppressed);
3170 }
Chris Wren333a61c2014-05-28 16:40:57 -04003171 }
3172
Chris Wren470c1ac2014-05-21 15:28:10 -04003173 // lock on mNotificationList
3174 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04003175 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04003176 }
3177
3178 private void scheduleSendRankingUpdate() {
Chris Wren52020492016-04-06 11:12:02 -04003179 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3180 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3181 mHandler.sendMessage(m);
3182 }
Chris Wrenf9536642014-04-17 10:01:54 -04003183 }
3184
3185 private void handleSendRankingUpdate() {
3186 synchronized (mNotificationList) {
Chris Wren333a61c2014-05-28 16:40:57 -04003187 mListeners.notifyRankingUpdateLocked();
Chris Wrenf9536642014-04-17 10:01:54 -04003188 }
3189 }
3190
John Spurlockd8afe3c2014-08-01 14:04:07 -04003191 private void scheduleListenerHintsChanged(int state) {
3192 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3193 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04003194 }
3195
Christoph Studer85a384b2014-08-27 20:16:15 +02003196 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3197 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3198 mHandler.obtainMessage(
3199 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3200 listenerInterruptionFilter,
3201 0).sendToTarget();
3202 }
3203
John Spurlockd8afe3c2014-08-01 14:04:07 -04003204 private void handleListenerHintsChanged(int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04003205 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003206 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04003207 }
3208 }
3209
Christoph Studer85a384b2014-08-27 20:16:15 +02003210 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3211 synchronized (mNotificationList) {
3212 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3213 }
3214 }
3215
Adam Lesinski182f73f2013-12-05 16:48:06 -08003216 private final class WorkerHandler extends Handler
3217 {
3218 @Override
3219 public void handleMessage(Message msg)
3220 {
3221 switch (msg.what)
3222 {
3223 case MESSAGE_TIMEOUT:
3224 handleTimeout((ToastRecord)msg.obj);
3225 break;
John Spurlock056c5192014-04-20 21:52:01 -04003226 case MESSAGE_SAVE_POLICY_FILE:
3227 handleSavePolicyFile();
3228 break;
Chris Wrenf9536642014-04-17 10:01:54 -04003229 case MESSAGE_SEND_RANKING_UPDATE:
3230 handleSendRankingUpdate();
3231 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04003232 case MESSAGE_LISTENER_HINTS_CHANGED:
3233 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04003234 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02003235 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3236 handleListenerInterruptionFilterChanged(msg.arg1);
3237 break;
Chris Wrenf9536642014-04-17 10:01:54 -04003238 }
3239 }
3240
3241 }
3242
Chris Wren51017d02015-12-15 15:34:46 -05003243 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04003244 {
Chris Wren51017d02015-12-15 15:34:46 -05003245 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04003246 super(looper);
3247 }
3248
3249 @Override
3250 public void handleMessage(Message msg) {
3251 switch (msg.what) {
3252 case MESSAGE_RECONSIDER_RANKING:
3253 handleRankingReconsideration(msg);
3254 break;
Chris Wren51017d02015-12-15 15:34:46 -05003255 case MESSAGE_RANKING_SORT:
3256 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04003257 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003258 }
3259 }
Chris Wren51017d02015-12-15 15:34:46 -05003260
3261 public void requestSort() {
3262 removeMessages(MESSAGE_RANKING_SORT);
3263 sendEmptyMessage(MESSAGE_RANKING_SORT);
3264 }
3265
3266 public void requestReconsideration(RankingReconsideration recon) {
3267 Message m = Message.obtain(this,
3268 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3269 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3270 sendMessageDelayed(m, delay);
3271 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003272 }
3273
Adam Lesinski182f73f2013-12-05 16:48:06 -08003274 // Notifications
3275 // ============================================================================
3276 static int clamp(int x, int low, int high) {
3277 return (x < low) ? low : ((x > high) ? high : x);
3278 }
3279
3280 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3281 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
svetoslavganov75986cf2009-05-14 22:28:01 -07003282 if (!manager.isEnabled()) {
3283 return;
3284 }
3285
3286 AccessibilityEvent event =
3287 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3288 event.setPackageName(packageName);
3289 event.setClassName(Notification.class.getName());
3290 event.setParcelableData(notification);
3291 CharSequence tickerText = notification.tickerText;
3292 if (!TextUtils.isEmpty(tickerText)) {
3293 event.getText().add(tickerText);
3294 }
3295
3296 manager.sendAccessibilityEvent(event);
3297 }
3298
Christoph Studer546bec82014-03-14 12:17:12 +01003299 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04003300
3301 // Record caller.
3302 recordCallerLocked(r);
3303
Joe Onorato46439ce2010-11-19 13:56:21 -08003304 // tell the app
3305 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003306 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08003307 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003308 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08003309 } catch (PendingIntent.CanceledException ex) {
3310 // do nothing - there's no relevant way to recover, and
3311 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04003312 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08003313 }
3314 }
3315 }
3316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003317 // status bar
Dan Sandlerd63f9322015-05-06 15:18:49 -04003318 if (r.getNotification().getSmallIcon() != null) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02003319 r.isCanceled = true;
Chris Wren333a61c2014-05-28 16:40:57 -04003320 mListeners.notifyRemovedLocked(r.sbn);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 }
3322
Chris Wren6054e612014-11-25 17:16:46 -05003323 final String canceledKey = r.getKey();
3324
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 // sound
Chris Wren6054e612014-11-25 17:16:46 -05003326 if (canceledKey.equals(mSoundNotificationKey)) {
3327 mSoundNotificationKey = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -07003328 final long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003330 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07003331 if (player != null) {
3332 player.stopAsync();
3333 }
3334 } catch (RemoteException e) {
3335 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 Binder.restoreCallingIdentity(identity);
3337 }
3338 }
3339
3340 // vibrate
Chris Wren6054e612014-11-25 17:16:46 -05003341 if (canceledKey.equals(mVibrateNotificationKey)) {
3342 mVibrateNotificationKey = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 long identity = Binder.clearCallingIdentity();
3344 try {
3345 mVibrator.cancel();
3346 }
3347 finally {
3348 Binder.restoreCallingIdentity(identity);
3349 }
3350 }
3351
3352 // light
Chris Wren6054e612014-11-25 17:16:46 -05003353 mLights.remove(canceledKey);
Daniel Sandler23d7c702013-03-07 16:32:06 -05003354
Christoph Studer546bec82014-03-14 12:17:12 +01003355 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04003356 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01003357 switch (reason) {
3358 case REASON_DELEGATE_CANCEL:
3359 case REASON_DELEGATE_CANCEL_ALL:
3360 case REASON_LISTENER_CANCEL:
3361 case REASON_LISTENER_CANCEL_ALL:
3362 mUsageStats.registerDismissedByUser(r);
3363 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05003364 case REASON_APP_CANCEL:
3365 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01003366 mUsageStats.registerRemovedByApp(r);
3367 break;
Christoph Studer546bec82014-03-14 12:17:12 +01003368 }
3369
Christoph Studercef37cf2014-07-25 14:18:17 +02003370 mNotificationsByKey.remove(r.sbn.getKey());
Christoph Studer265c1052014-07-23 17:14:33 +02003371 String groupKey = r.getGroupKey();
3372 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3373 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3374 mSummaryByGroupKey.remove(groupKey);
3375 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04003376 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3377 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3378 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04003379 }
Christoph Studercef37cf2014-07-25 14:18:17 +02003380
Daniel Sandler23d7c702013-03-07 16:32:06 -05003381 // Save it for users of getHistoricalNotifications()
3382 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02003383
Chris Wren6650e572015-05-15 17:19:25 -04003384 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -04003385 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3386 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003387 }
3388
3389 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07003390 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003391 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 */
John Spurlocke6a7d932014-03-13 12:29:00 -04003393 void cancelNotification(final int callingUid, final int callingPid,
3394 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003395 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04003396 final int userId, final int reason, final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003397 // In enqueueNotificationInternal notifications are added by scheduling the
3398 // work on the worker handler. Hence, we also schedule the cancel on this
3399 // handler to avoid a scenario where an add notification call followed by a
3400 // remove notification call ends up in not removing the notification.
3401 mHandler.post(new Runnable() {
3402 @Override
3403 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003404 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08003405 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3406 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003408 synchronized (mNotificationList) {
3409 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3410 if (index >= 0) {
3411 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003412
Christoph Studer546bec82014-03-14 12:17:12 +01003413 // Ideally we'd do this in the caller of this method. However, that would
3414 // require the caller to also find the notification.
3415 if (reason == REASON_DELEGATE_CLICK) {
3416 mUsageStats.registerClickedByUser(r);
3417 }
3418
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003419 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3420 return;
3421 }
3422 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3423 return;
3424 }
3425
3426 mNotificationList.remove(index);
3427
Selim Cinek3f19f602016-05-02 18:01:56 -07003428 cancelNotificationLocked(r, sendDelete, reason);
Christoph Studer265c1052014-07-23 17:14:33 +02003429 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003430 REASON_GROUP_SUMMARY_CANCELED, sendDelete);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003431 updateLightsLocked();
3432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003434 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003435 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 }
3437
3438 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07003439 * Determine whether the userId applies to the notification in question, either because
3440 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3441 */
3442 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3443 return
3444 // looking for USER_ALL notifications? match everything
3445 userId == UserHandle.USER_ALL
3446 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003447 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07003448 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003449 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07003450 }
3451
3452 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003453 * Determine whether the userId applies to the notification in question, either because
3454 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01003455 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003456 */
Kenny Guy2a764942014-04-02 13:29:20 +01003457 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00003458 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04003459 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003460 }
3461
3462 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05003463 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003464 * {@code mustHaveFlags}.
3465 */
John Spurlocke6a7d932014-03-13 12:29:00 -04003466 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
Julia Reynoldsef37f282016-02-12 09:11:27 -05003467 int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04003468 ManagedServiceInfo listener) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003469 String listenerName = listener == null ? null : listener.component.toShortString();
John Spurlocke6a7d932014-03-13 12:29:00 -04003470 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3471 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
Christoph Studere4ef156b2014-07-04 18:41:57 +02003472 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473
3474 synchronized (mNotificationList) {
3475 final int N = mNotificationList.size();
Christoph Studere4ef156b2014-07-04 18:41:57 +02003476 ArrayList<NotificationRecord> canceledNotifications = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 for (int i = N-1; i >= 0; --i) {
3478 NotificationRecord r = mNotificationList.get(i);
Daniel Sandler321e9c52012-10-12 10:59:26 -07003479 if (!notificationMatchesUserId(r, userId)) {
Dianne Hackborn41203752012-08-31 14:05:51 -07003480 continue;
3481 }
Amith Yamasani5ec00e92012-11-07 16:58:30 -08003482 // Don't remove notifications to all, if there's no package name specified
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003483 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
Amith Yamasani5ec00e92012-11-07 16:58:30 -08003484 continue;
3485 }
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003486 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 continue;
3488 }
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003489 if ((r.getFlags() & mustNotHaveFlags) != 0) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07003490 continue;
3491 }
Daniel Sandler4f91efd2013-04-25 16:38:41 -04003492 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 continue;
3494 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003495 if (canceledNotifications == null) {
3496 canceledNotifications = new ArrayList<>();
3497 }
3498 canceledNotifications.add(r);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08003499 if (!doit) {
3500 return true;
3501 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003502 mNotificationList.remove(i);
Christoph Studer546bec82014-03-14 12:17:12 +01003503 cancelNotificationLocked(r, false, reason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003505 if (doit && canceledNotifications != null) {
3506 final int M = canceledNotifications.size();
3507 for (int i = 0; i < M; i++) {
3508 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003509 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003510 }
3511 }
3512 if (canceledNotifications != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513 updateLightsLocked();
3514 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003515 return canceledNotifications != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 }
3517 }
3518
Adam Lesinski350159c2014-03-27 11:15:11 -07003519 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04003520 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003521 String listenerName = listener == null ? null : listener.component.toShortString();
John Spurlocke6a7d932014-03-13 12:29:00 -04003522 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
Christoph Studere4ef156b2014-07-04 18:41:57 +02003523 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01003524
Christoph Studere4ef156b2014-07-04 18:41:57 +02003525 ArrayList<NotificationRecord> canceledNotifications = null;
Adam Lesinskie8240262014-03-26 16:01:00 -07003526 final int N = mNotificationList.size();
3527 for (int i=N-1; i>=0; i--) {
3528 NotificationRecord r = mNotificationList.get(i);
Kenny Guya263e4e2014-03-03 18:24:03 +00003529 if (includeCurrentProfiles) {
3530 if (!notificationMatchesCurrentProfiles(r, userId)) {
3531 continue;
3532 }
3533 } else {
3534 if (!notificationMatchesUserId(r, userId)) {
3535 continue;
3536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003537 }
3538
Adam Lesinskie8240262014-03-26 16:01:00 -07003539 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3540 | Notification.FLAG_NO_CLEAR)) == 0) {
3541 mNotificationList.remove(i);
Christoph Studer546bec82014-03-14 12:17:12 +01003542 cancelNotificationLocked(r, true, reason);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003543 // Make a note so we can cancel children later.
3544 if (canceledNotifications == null) {
3545 canceledNotifications = new ArrayList<>();
3546 }
3547 canceledNotifications.add(r);
Adam Lesinskie8240262014-03-26 16:01:00 -07003548 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003550 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3551 for (int i = 0; i < M; i++) {
3552 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003553 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003554 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003555 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 }
3557
Christoph Studere4ef156b2014-07-04 18:41:57 +02003558 // Warning: The caller is responsible for invoking updateLightsLocked().
3559 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003560 String listenerName, int reason, boolean sendDelete) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003561 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02003562 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003563 return;
3564 }
3565
3566 String pkg = r.sbn.getPackageName();
3567 int userId = r.getUserId();
3568
3569 if (pkg == null) {
3570 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3571 return;
3572 }
3573
3574 final int N = mNotificationList.size();
3575 for (int i = N - 1; i >= 0; i--) {
3576 NotificationRecord childR = mNotificationList.get(i);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003577 StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003578 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Selim Cinek1d359792017-01-13 14:43:43 -08003579 childR.getGroupKey().equals(r.getGroupKey())
3580 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
Christoph Studer265c1052014-07-23 17:14:33 +02003581 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3582 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003583 mNotificationList.remove(i);
Selim Cinekce87a8a2016-06-20 15:40:07 -07003584 cancelNotificationLocked(childR, sendDelete, reason);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003585 }
3586 }
3587 }
3588
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 // lock on mNotificationList
Adam Lesinski182f73f2013-12-05 16:48:06 -08003590 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 {
The Android Open Source Project10592532009-03-18 17:39:46 -07003592 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05003593 NotificationRecord ledNotification = null;
3594 while (ledNotification == null && !mLights.isEmpty()) {
3595 final String owner = mLights.get(mLights.size() - 1);
3596 ledNotification = mNotificationsByKey.get(owner);
3597 if (ledNotification == null) {
3598 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3599 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 }
3601 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05003602
Mike Lockwood63b5ad92011-08-30 09:55:30 -04003603 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05003604 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05003605 mNotificationLight.turnOff();
Wei Liu97e56662016-03-04 10:52:33 -08003606 if (mStatusBar != null) {
3607 mStatusBar.notificationLightOff();
3608 }
The Android Open Source Project10592532009-03-18 17:39:46 -07003609 } else {
Chris Wren6054e612014-11-25 17:16:46 -05003610 final Notification ledno = ledNotification.sbn.getNotification();
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003611 int ledARGB = ledno.ledARGB;
3612 int ledOnMS = ledno.ledOnMS;
3613 int ledOffMS = ledno.ledOffMS;
3614 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
Mike Lockwood670f9322010-01-20 12:13:36 -05003615 ledARGB = mDefaultNotificationColor;
3616 ledOnMS = mDefaultNotificationLedOn;
3617 ledOffMS = mDefaultNotificationLedOff;
3618 }
3619 if (mNotificationPulseEnabled) {
3620 // pulse repeatedly
Adam Lesinski182f73f2013-12-05 16:48:06 -08003621 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
Mike Lockwood670f9322010-01-20 12:13:36 -05003622 ledOnMS, ledOffMS);
Mike Lockwood670f9322010-01-20 12:13:36 -05003623 }
Wei Liu97e56662016-03-04 10:52:33 -08003624 if (mStatusBar != null) {
3625 // let SystemUI make an independent decision
3626 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3627 }
The Android Open Source Project10592532009-03-18 17:39:46 -07003628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003629 }
3630
3631 // lock on mNotificationList
Adam Lesinski182f73f2013-12-05 16:48:06 -08003632 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003633 {
3634 ArrayList<NotificationRecord> list = mNotificationList;
3635 final int len = list.size();
3636 for (int i=0; i<len; i++) {
3637 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01003638 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3639 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003640 return i;
3641 }
3642 }
3643 return -1;
3644 }
3645
Christoph Studer71f18fd2014-05-20 17:02:04 +02003646 // lock on mNotificationList
3647 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02003648 final int N = mNotificationList.size();
3649 for (int i = 0; i < N; i++) {
3650 if (key.equals(mNotificationList.get(i).getKey())) {
3651 return i;
3652 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02003653 }
Christoph Studerc5115552014-06-12 20:22:31 +02003654 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02003655 }
3656
Mike Lockwoodc22404a2009-12-02 11:15:02 -05003657 private void updateNotificationPulse() {
3658 synchronized (mNotificationList) {
3659 updateLightsLocked();
3660 }
3661 }
John Spurlocke677d712014-02-13 12:52:19 -05003662
John Spurlock7340fc82014-04-24 18:50:12 -04003663 private static boolean isUidSystem(int uid) {
3664 final int appid = UserHandle.getAppId(uid);
3665 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3666 }
John Spurlockb408e8e2014-04-23 21:12:45 -04003667
John Spurlock7340fc82014-04-24 18:50:12 -04003668 private static boolean isCallerSystem() {
3669 return isUidSystem(Binder.getCallingUid());
3670 }
3671
3672 private static void checkCallerIsSystem() {
3673 if (isCallerSystem()) {
3674 return;
3675 }
3676 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3677 }
3678
3679 private static void checkCallerIsSystemOrSameApp(String pkg) {
3680 if (isCallerSystem()) {
3681 return;
3682 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003683 checkCallerIsSameApp(pkg);
3684 }
3685
3686 private static void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04003687 final int uid = Binder.getCallingUid();
3688 try {
3689 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3690 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04003691 if (ai == null) {
3692 throw new SecurityException("Unknown package " + pkg);
3693 }
John Spurlock7340fc82014-04-24 18:50:12 -04003694 if (!UserHandle.isSameApp(ai.uid, uid)) {
3695 throw new SecurityException("Calling uid " + uid + " gave package"
3696 + pkg + " which is owned by uid " + ai.uid);
3697 }
3698 } catch (RemoteException re) {
3699 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3700 }
3701 }
3702
John Spurlock32fe4c62014-10-02 12:16:02 -04003703 private static String callStateToString(int state) {
3704 switch (state) {
3705 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3706 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3707 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3708 default: return "CALL_STATE_UNKNOWN_" + state;
3709 }
3710 }
3711
3712 private void listenForCallState() {
3713 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3714 @Override
3715 public void onCallStateChanged(int state, String incomingNumber) {
3716 if (mCallState == state) return;
3717 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3718 mCallState = state;
3719 }
3720 }, PhoneStateListener.LISTEN_CALL_STATE);
3721 }
3722
Christoph Studer05ad4822014-05-16 14:16:03 +02003723 /**
3724 * Generates a NotificationRankingUpdate from 'sbns', considering only
3725 * notifications visible to the given listener.
Chris Wren333a61c2014-05-28 16:40:57 -04003726 *
3727 * <p>Caller must hold a lock on mNotificationList.</p>
Christoph Studer05ad4822014-05-16 14:16:03 +02003728 */
Chris Wren333a61c2014-05-28 16:40:57 -04003729 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04003730 final int N = mNotificationList.size();
3731 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02003732 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05003733 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003734 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003735 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003736 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05003737 Bundle explanation = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04003738 for (int i = 0; i < N; i++) {
3739 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02003740 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02003741 continue;
3742 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003743 final String key = record.sbn.getKey();
3744 keys.add(key);
3745 importance.add(record.getImportance());
3746 if (record.getImportanceExplanation() != null) {
3747 explanation.putCharSequence(key, record.getImportanceExplanation());
3748 }
Chris Wren333a61c2014-05-28 16:40:57 -04003749 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05003750 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003751
Christoph Studer05ad4822014-05-16 14:16:03 +02003752 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003753 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003754 if (record.getPackageVisibilityOverride()
3755 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05003756 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003757 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003758 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Christoph Studer05ad4822014-05-16 14:16:03 +02003759 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003760 final int M = keys.size();
3761 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02003762 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05003763 int[] importanceAr = new int[M];
3764 for (int i = 0; i < M; i++) {
3765 importanceAr[i] = importance.get(i);
3766 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003767 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003768 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
Christoph Studer05ad4822014-05-16 14:16:03 +02003769 }
3770
Christoph Studercef37cf2014-07-25 14:18:17 +02003771 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3772 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3773 return false;
3774 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07003775 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02003776 return true;
3777 }
3778
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00003779 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003780 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003781 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00003782 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003783 } catch (RemoteException re) {
3784 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00003785 } catch (IllegalArgumentException ex) {
3786 // Package not found.
3787 return false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003788 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003789 }
3790
Chris Wren47633422016-01-22 09:56:59 -05003791 private class TrimCache {
3792 StatusBarNotification heavy;
3793 StatusBarNotification sbnClone;
3794 StatusBarNotification sbnCloneLight;
3795
3796 TrimCache(StatusBarNotification sbn) {
3797 heavy = sbn;
3798 }
3799
3800 StatusBarNotification ForListener(ManagedServiceInfo info) {
3801 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3802 if (sbnCloneLight == null) {
3803 sbnCloneLight = heavy.cloneLight();
3804 }
3805 return sbnCloneLight;
3806 } else {
3807 if (sbnClone == null) {
3808 sbnClone = heavy.clone();
3809 }
3810 return sbnClone;
3811 }
3812 }
3813 }
3814
Chris Wren0efdb882016-03-01 17:17:47 -05003815 public class NotificationRankers extends ManagedServices {
Chris Wren51017d02015-12-15 15:34:46 -05003816
Chris Wren0efdb882016-03-01 17:17:47 -05003817 public NotificationRankers() {
Chris Wren51017d02015-12-15 15:34:46 -05003818 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3819 }
3820
3821 @Override
3822 protected Config getConfig() {
3823 Config c = new Config();
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003824 c.caption = "notification ranker service";
3825 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3826 c.secureSettingName = null;
3827 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05003828 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003829 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05003830 return c;
3831 }
3832
3833 @Override
3834 protected IInterface asInterface(IBinder binder) {
3835 return INotificationListener.Stub.asInterface(binder);
3836 }
3837
3838 @Override
3839 protected boolean checkType(IInterface service) {
3840 return service instanceof INotificationListener;
3841 }
3842
3843 @Override
3844 protected void onServiceAdded(ManagedServiceInfo info) {
3845 mListeners.registerGuestService(info);
3846 }
3847
3848 @Override
3849 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3850 mListeners.unregisterService(removed.service, removed.userid);
3851 }
Chris Wren47633422016-01-22 09:56:59 -05003852
3853 public void onNotificationEnqueued(final NotificationRecord r) {
3854 final StatusBarNotification sbn = r.sbn;
3855 TrimCache trimCache = new TrimCache(sbn);
3856
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003857 // mServices is the list inside ManagedServices of all the rankers,
Chris Wren47633422016-01-22 09:56:59 -05003858 // There should be only one, but it's a list, so while we enforce
3859 // singularity elsewhere, we keep it general here, to avoid surprises.
Chris Wren0efdb882016-03-01 17:17:47 -05003860 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
Chris Wren47633422016-01-22 09:56:59 -05003861 boolean sbnVisible = isVisibleToListener(sbn, info);
3862 if (!sbnVisible) {
3863 continue;
3864 }
3865
3866 final int importance = r.getImportance();
3867 final boolean fromUser = r.isImportanceFromUser();
3868 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003869 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05003870 @Override
3871 public void run() {
3872 notifyEnqueued(info, sbnToPost, importance, fromUser);
3873 }
3874 });
3875 }
3876 }
3877
3878 private void notifyEnqueued(final ManagedServiceInfo info,
3879 final StatusBarNotification sbn, int importance, boolean fromUser) {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003880 final INotificationListener ranker = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05003881 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3882 try {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003883 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
Chris Wren47633422016-01-22 09:56:59 -05003884 } catch (RemoteException ex) {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003885 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
Chris Wren47633422016-01-22 09:56:59 -05003886 }
3887 }
3888
3889 public boolean isEnabled() {
3890 return !mServices.isEmpty();
3891 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003892
3893 @Override
3894 public void onUserSwitched(int user) {
Julia Reynoldsad929572016-05-26 13:49:17 -04003895 synchronized (mNotificationList) {
Julia Reynolds00d9d9f2016-06-21 07:47:22 -04003896 int i = mServices.size()-1;
3897 while (i --> 0) {
3898 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldsad929572016-05-26 13:49:17 -04003899 unregisterService(info.service, info.userid);
3900 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003901 }
3902 registerRanker();
3903 }
3904
3905 @Override
Julia Reynolds6434eb22016-08-08 17:19:26 -04003906 public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
3907 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003908 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
Chris Wren88d2f6d2016-03-17 15:47:09 -04003909 if (mRankerServicePackageName == null) {
3910 return;
3911 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003912
Julia Reynolds6434eb22016-08-08 17:19:26 -04003913 if (pkgList != null && (pkgList.length > 0) && !removingPackage) {
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003914 for (String pkgName : pkgList) {
3915 if (mRankerServicePackageName.equals(pkgName)) {
3916 registerRanker();
3917 }
3918 }
3919 }
3920 }
3921
3922 protected void registerRanker() {
3923 // Find the updatable ranker and register it.
Chris Wren88d2f6d2016-03-17 15:47:09 -04003924 if (mRankerServicePackageName == null) {
3925 Slog.w(TAG, "could not start ranker service: no package specified!");
3926 return;
3927 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003928 Set<ComponentName> rankerComponents = queryPackageForServices(
Julia Reynoldsa3dc1fb2016-04-12 10:25:12 -04003929 mRankerServicePackageName, UserHandle.USER_SYSTEM);
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003930 Iterator<ComponentName> iterator = rankerComponents.iterator();
3931 if (iterator.hasNext()) {
3932 ComponentName rankerComponent = iterator.next();
3933 if (iterator.hasNext()) {
3934 Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3935 } else {
3936 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3937 }
3938 } else {
3939 Slog.w(TAG, "could not start ranker service: none found");
3940 }
3941 }
Chris Wren51017d02015-12-15 15:34:46 -05003942 }
3943
John Spurlock7340fc82014-04-24 18:50:12 -04003944 public class NotificationListeners extends ManagedServices {
3945
Christoph Studerb82bc782014-08-20 14:29:43 +02003946 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3947
John Spurlock7340fc82014-04-24 18:50:12 -04003948 public NotificationListeners() {
3949 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3950 }
3951
3952 @Override
3953 protected Config getConfig() {
3954 Config c = new Config();
3955 c.caption = "notification listener";
3956 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3957 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3958 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3959 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3960 c.clientLabel = R.string.notification_listener_binding_label;
3961 return c;
3962 }
3963
3964 @Override
3965 protected IInterface asInterface(IBinder binder) {
3966 return INotificationListener.Stub.asInterface(binder);
3967 }
3968
3969 @Override
Chris Wren51017d02015-12-15 15:34:46 -05003970 protected boolean checkType(IInterface service) {
3971 return service instanceof INotificationListener;
3972 }
3973
3974 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04003975 public void onServiceAdded(ManagedServiceInfo info) {
3976 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04003977 final NotificationRankingUpdate update;
Christoph Studer05ad4822014-05-16 14:16:03 +02003978 synchronized (mNotificationList) {
Chris Wren333a61c2014-05-28 16:40:57 -04003979 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02003980 }
John Spurlock7340fc82014-04-24 18:50:12 -04003981 try {
Chris Wren333a61c2014-05-28 16:40:57 -04003982 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04003983 } catch (RemoteException e) {
3984 // we tried
3985 }
3986 }
3987
John Spurlock1fa865f2014-07-21 14:56:39 -04003988 @Override
3989 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003990 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003991 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01003992 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04003993 }
Christoph Studerb82bc782014-08-20 14:29:43 +02003994 mLightTrimListeners.remove(removed);
3995 }
3996
3997 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3998 if (trim == TRIM_LIGHT) {
3999 mLightTrimListeners.add(info);
4000 } else {
4001 mLightTrimListeners.remove(info);
4002 }
4003 }
4004
4005 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
4006 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04004007 }
4008
John Spurlock7340fc82014-04-24 18:50:12 -04004009 /**
4010 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02004011 *
4012 * <p>
4013 * Also takes care of removing a notification that has been visible to a listener before,
4014 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04004015 */
Christoph Studercef37cf2014-07-25 14:18:17 +02004016 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
Christoph Studerb82bc782014-08-20 14:29:43 +02004017 // Lazily initialized snapshots of the notification.
Chris Wren47633422016-01-22 09:56:59 -05004018 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02004019
John Spurlock7340fc82014-04-24 18:50:12 -04004020 for (final ManagedServiceInfo info : mServices) {
Christoph Studercef37cf2014-07-25 14:18:17 +02004021 boolean sbnVisible = isVisibleToListener(sbn, info);
4022 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
4023 // This notification hasn't been and still isn't visible -> ignore.
4024 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02004025 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04004026 }
Chris Wren333a61c2014-05-28 16:40:57 -04004027 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02004028
4029 // This notification became invisible -> remove the old one.
4030 if (oldSbnVisible && !sbnVisible) {
4031 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4032 mHandler.post(new Runnable() {
4033 @Override
4034 public void run() {
4035 notifyRemoved(info, oldSbnLightClone, update);
4036 }
4037 });
Christoph Studer05ad4822014-05-16 14:16:03 +02004038 continue;
4039 }
Christoph Studercef37cf2014-07-25 14:18:17 +02004040
Chris Wren47633422016-01-22 09:56:59 -05004041 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02004042 mHandler.post(new Runnable() {
4043 @Override
4044 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02004045 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02004046 }
4047 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004048 }
4049 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004050
John Spurlock7340fc82014-04-24 18:50:12 -04004051 /**
4052 * asynchronously notify all listeners about a removed notification
4053 */
Chris Wren333a61c2014-05-28 16:40:57 -04004054 public void notifyRemovedLocked(StatusBarNotification sbn) {
John Spurlock7340fc82014-04-24 18:50:12 -04004055 // make a copy in case changes are made to the underlying Notification object
4056 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4057 // notification
4058 final StatusBarNotification sbnLight = sbn.cloneLight();
Chris Wrenf9536642014-04-17 10:01:54 -04004059 for (final ManagedServiceInfo info : mServices) {
Christoph Studercef37cf2014-07-25 14:18:17 +02004060 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02004061 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04004062 }
Chris Wren333a61c2014-05-28 16:40:57 -04004063 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02004064 mHandler.post(new Runnable() {
4065 @Override
4066 public void run() {
Christoph Studercef37cf2014-07-25 14:18:17 +02004067 notifyRemoved(info, sbnLight, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02004068 }
4069 });
Chris Wrenf9536642014-04-17 10:01:54 -04004070 }
4071 }
4072
4073 /**
4074 * asynchronously notify all listeners about a reordering of notifications
Chris Wrenf9536642014-04-17 10:01:54 -04004075 */
Chris Wren333a61c2014-05-28 16:40:57 -04004076 public void notifyRankingUpdateLocked() {
Chris Wrenf9536642014-04-17 10:01:54 -04004077 for (final ManagedServiceInfo serviceInfo : mServices) {
Christoph Studer05ad4822014-05-16 14:16:03 +02004078 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4079 continue;
4080 }
Christoph Studercef37cf2014-07-25 14:18:17 +02004081 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
John Spurlock7340fc82014-04-24 18:50:12 -04004082 mHandler.post(new Runnable() {
4083 @Override
4084 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -04004085 notifyRankingUpdate(serviceInfo, update);
John Spurlock7340fc82014-04-24 18:50:12 -04004086 }
4087 });
Kenny Guya263e4e2014-03-03 18:24:03 +00004088 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004089 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004090
John Spurlockd8afe3c2014-08-01 14:04:07 -04004091 public void notifyListenerHintsChangedLocked(final int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04004092 for (final ManagedServiceInfo serviceInfo : mServices) {
4093 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4094 continue;
4095 }
4096 mHandler.post(new Runnable() {
4097 @Override
4098 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004099 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004100 }
4101 });
4102 }
4103 }
4104
Christoph Studer85a384b2014-08-27 20:16:15 +02004105 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4106 for (final ManagedServiceInfo serviceInfo : mServices) {
4107 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4108 continue;
4109 }
4110 mHandler.post(new Runnable() {
4111 @Override
4112 public void run() {
4113 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4114 }
4115 });
4116 }
4117 }
4118
Christoph Studercef37cf2014-07-25 14:18:17 +02004119 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02004120 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
John Spurlock7340fc82014-04-24 18:50:12 -04004121 final INotificationListener listener = (INotificationListener)info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004122 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04004123 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07004124 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04004125 } catch (RemoteException ex) {
4126 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4127 }
4128 }
4129
Christoph Studercef37cf2014-07-25 14:18:17 +02004130 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Christoph Studer05ad4822014-05-16 14:16:03 +02004131 NotificationRankingUpdate rankingUpdate) {
John Spurlock7340fc82014-04-24 18:50:12 -04004132 if (!info.enabledAndUserMatches(sbn.getUserId())) {
4133 return;
4134 }
Christoph Studer05ad4822014-05-16 14:16:03 +02004135 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004136 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04004137 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07004138 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04004139 } catch (RemoteException ex) {
4140 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04004141 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004142 }
Chris Wrenf9536642014-04-17 10:01:54 -04004143
Christoph Studer05ad4822014-05-16 14:16:03 +02004144 private void notifyRankingUpdate(ManagedServiceInfo info,
4145 NotificationRankingUpdate rankingUpdate) {
4146 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04004147 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02004148 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04004149 } catch (RemoteException ex) {
4150 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4151 }
4152 }
John Spurlock1fa865f2014-07-21 14:56:39 -04004153
John Spurlockd8afe3c2014-08-01 14:04:07 -04004154 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04004155 final INotificationListener listener = (INotificationListener) info.service;
4156 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004157 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004158 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004159 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04004160 }
4161 }
Justin Koh38156c52014-06-04 13:57:49 -07004162
Christoph Studer85a384b2014-08-27 20:16:15 +02004163 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4164 int interruptionFilter) {
4165 final INotificationListener listener = (INotificationListener) info.service;
4166 try {
4167 listener.onInterruptionFilterChanged(interruptionFilter);
4168 } catch (RemoteException ex) {
4169 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4170 }
4171 }
4172
Justin Koh38156c52014-06-04 13:57:49 -07004173 private boolean isListenerPackage(String packageName) {
4174 if (packageName == null) {
4175 return false;
4176 }
4177 // TODO: clean up locking object later
4178 synchronized (mNotificationList) {
4179 for (final ManagedServiceInfo serviceInfo : mServices) {
4180 if (packageName.equals(serviceInfo.component.getPackageName())) {
4181 return true;
4182 }
4183 }
4184 }
4185 return false;
4186 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004187 }
John Spurlock25e2d242014-06-27 13:58:23 -04004188
4189 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04004190 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04004191 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04004192 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04004193 public long since;
4194 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04004195 public boolean redact = true;
John Spurlock25e2d242014-06-27 13:58:23 -04004196
4197 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04004198 final DumpFilter filter = new DumpFilter();
4199 for (int ai = 0; ai < args.length; ai++) {
4200 final String a = args[ai];
4201 if ("--noredact".equals(a) || "--reveal".equals(a)) {
4202 filter.redact = false;
4203 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4204 if (ai < args.length-1) {
4205 ai++;
4206 filter.pkgFilter = args[ai].trim().toLowerCase();
4207 if (filter.pkgFilter.isEmpty()) {
4208 filter.pkgFilter = null;
4209 } else {
4210 filter.filtered = true;
4211 }
4212 }
4213 } else if ("--zen".equals(a) || "zen".equals(a)) {
4214 filter.filtered = true;
4215 filter.zen = true;
4216 } else if ("--stats".equals(a)) {
4217 filter.stats = true;
4218 if (ai < args.length-1) {
4219 ai++;
4220 filter.since = Long.valueOf(args[ai]);
4221 } else {
4222 filter.since = 0;
4223 }
4224 }
John Spurlock25e2d242014-06-27 13:58:23 -04004225 }
Dan Sandlera1770312015-07-10 13:59:29 -04004226 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04004227 }
4228
4229 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04004230 if (!filtered) return true;
4231 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04004232 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04004233 }
4234
4235 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04004236 if (!filtered) return true;
4237 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04004238 }
4239
4240 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04004241 if (!filtered) return true;
4242 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04004243 }
4244
4245 @Override
4246 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04004247 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04004248 }
4249 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07004250
4251 /**
4252 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4253 * binder without sending large amounts of data over a oneway transaction.
4254 */
4255 private static final class StatusBarNotificationHolder
4256 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07004257 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004258
4259 public StatusBarNotificationHolder(StatusBarNotification value) {
4260 mValue = value;
4261 }
4262
Griff Hazene9aac5f2014-09-05 20:04:09 -07004263 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07004264 @Override
4265 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07004266 StatusBarNotification value = mValue;
4267 mValue = null;
4268 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004269 }
4270 }
John Spurlock7c74f782015-06-04 13:01:42 -04004271
4272 private final class PolicyAccess {
4273 private static final String SEPARATOR = ":";
4274 private final String[] PERM = {
4275 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4276 };
4277
4278 public boolean isPackageGranted(String pkg) {
4279 return pkg != null && getGrantedPackages().contains(pkg);
4280 }
4281
4282 public void put(String pkg, boolean granted) {
4283 if (pkg == null) return;
4284 final ArraySet<String> pkgs = getGrantedPackages();
4285 boolean changed;
4286 if (granted) {
4287 changed = pkgs.add(pkg);
4288 } else {
4289 changed = pkgs.remove(pkg);
4290 }
4291 if (!changed) return;
4292 final String setting = TextUtils.join(SEPARATOR, pkgs);
4293 final int currentUser = ActivityManager.getCurrentUser();
4294 Settings.Secure.putStringForUser(getContext().getContentResolver(),
4295 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4296 setting,
4297 currentUser);
4298 getContext().sendBroadcastAsUser(new Intent(NotificationManager
4299 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4300 .setPackage(pkg)
4301 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4302 }
4303
4304 public ArraySet<String> getGrantedPackages() {
4305 final ArraySet<String> pkgs = new ArraySet<>();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04004306
4307 long identity = Binder.clearCallingIdentity();
4308 try {
4309 final String setting = Settings.Secure.getStringForUser(
4310 getContext().getContentResolver(),
4311 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4312 ActivityManager.getCurrentUser());
4313 if (setting != null) {
4314 final String[] tokens = setting.split(SEPARATOR);
4315 for (int i = 0; i < tokens.length; i++) {
4316 String token = tokens[i];
4317 if (token != null) {
Andreas Gampe1ed71f32015-12-11 15:49:07 -08004318 token = token.trim();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04004319 }
4320 if (TextUtils.isEmpty(token)) {
4321 continue;
4322 }
4323 pkgs.add(token);
John Spurlock7c74f782015-06-04 13:01:42 -04004324 }
John Spurlock7c74f782015-06-04 13:01:42 -04004325 }
Julia Reynoldsea6c4482015-08-13 09:01:33 -04004326 } finally {
4327 Binder.restoreCallingIdentity(identity);
John Spurlock7c74f782015-06-04 13:01:42 -04004328 }
4329 return pkgs;
4330 }
4331
4332 public String[] getRequestingPackages() throws RemoteException {
4333 final ParceledListSlice list = AppGlobals.getPackageManager()
4334 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4335 ActivityManager.getCurrentUser());
4336 final List<PackageInfo> pkgs = list.getList();
4337 if (pkgs == null || pkgs.isEmpty()) return new String[0];
4338 final int N = pkgs.size();
4339 final String[] rt = new String[N];
4340 for (int i = 0; i < N; i++) {
4341 rt[i] = pkgs.get(i).packageName;
4342 }
4343 return rt;
4344 }
4345 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004346}