blob: add8b90f909616fdf1f7bdf8a2edddd45b79a87c [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;
Svet Ganovb3b22cb2016-07-14 16:08:09 -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;
John Spurlockb408e8e2014-04-23 21:12:45 -0400141import com.android.server.statusbar.StatusBarManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800142import com.android.server.vr.VrManagerInternal;
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 Wren763a9bb2016-05-31 17:14:12 -0400183 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 50f;
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
Adam Lesinski182f73f2013-12-05 16:48:06 -0800196 static final int LONG_DELAY = 3500; // 3.5 seconds
197 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;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800234 private VrManagerInternal mVrManagerInternal;
Svet Ganovb3b22cb2016-07-14 16:08:09 -0700235 private WindowManagerInternal mWindowManagerInternal;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 final IBinder mForegroundToken = new Binder();
Chris Wren93bb8b82016-03-29 14:35:05 -0400238 private Handler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400239 private final HandlerThread mRankingThread = new HandlerThread("ranker",
240 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
Adam Lesinski182f73f2013-12-05 16:48:06 -0800242 private Light mNotificationLight;
243 Light mAttentionLight;
Mike Lockwood670f9322010-01-20 12:13:36 -0500244 private int mDefaultNotificationColor;
245 private int mDefaultNotificationLedOn;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800246
Mike Lockwood670f9322010-01-20 12:13:36 -0500247 private int mDefaultNotificationLedOff;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800248 private long[] mDefaultVibrationPattern;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800249
Daniel Sandleredbb3802012-11-13 20:49:47 -0800250 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400251 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800252 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800253
John Spurlockd8afe3c2014-08-01 14:04:07 -0400254 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400255 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500256 private String mSoundNotificationKey;
257 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
Bryce Lee7219ada2016-04-08 10:54:23 -0700259 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
260 new SparseArray<ArraySet<ManagedServiceInfo>>();
261 private List<ComponentName> mEffectsSuppressors = new ArrayList<ComponentName>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400262 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500263 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400264
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500265 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400266 private boolean mScreenOn = true;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500267 private boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500268 private boolean mNotificationPulseEnabled;
269
Daniel Sandler09a247e2013-02-14 10:24:17 -0500270 // used as a mutex for access to all active notifications & listeners
Adam Lesinski182f73f2013-12-05 16:48:06 -0800271 final ArrayList<NotificationRecord> mNotificationList =
Fred Quintana6ecaff12009-09-25 14:23:13 -0700272 new ArrayList<NotificationRecord>();
John Spurlocka4294292014-03-24 18:02:32 -0400273 final ArrayMap<String, NotificationRecord> mNotificationsByKey =
274 new ArrayMap<String, NotificationRecord>();
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400275 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800276 final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
Christoph Studer265c1052014-07-23 17:14:33 +0200277 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
John Spurlock7c74f782015-06-04 13:01:42 -0400278 final PolicyAccess mPolicyAccess = new PolicyAccess();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
Chris Wren6054e612014-11-25 17:16:46 -0500280 // The last key in this list owns the hardware.
281 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700282
Adam Lesinski182f73f2013-12-05 16:48:06 -0800283 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700284 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500285
Griff Hazen9f637d12014-06-10 11:13:51 -0700286 private Archive mArchive;
287
John Spurlock21258a32015-05-27 18:22:55 -0400288 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400289 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400290
Daniel Sandler0da673f2012-04-11 12:33:16 -0400291 private static final int DB_VERSION = 1;
292
John Spurlock21258a32015-05-27 18:22:55 -0400293 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400294 private static final String ATTR_VERSION = "version";
295
Chris Wren54bbef42014-07-09 18:37:56 -0400296 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400297
John Spurlockb408e8e2014-04-23 21:12:45 -0400298 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400299 private NotificationListeners mListeners;
Chris Wren0efdb882016-03-01 17:17:47 -0500300 private NotificationRankers mRankerServices;
John Spurlock7340fc82014-04-24 18:50:12 -0400301 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200302 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100303
John Spurlocke6a7d932014-03-13 12:29:00 -0400304 private static final int MY_UID = Process.myUid();
305 private static final int MY_PID = Process.myPid();
Chris Wren51017d02015-12-15 15:34:46 -0500306 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400307 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400308 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
Chris Wrend4054312016-06-24 17:07:40 -0400309 private String mSystemNotificationSound;
John Spurlocke6a7d932014-03-13 12:29:00 -0400310
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500311 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700312 final int mBufferSize;
313 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500314
Griff Hazen9f637d12014-06-10 11:13:51 -0700315 public Archive(int size) {
316 mBufferSize = size;
317 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500318 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700319
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400320 public String toString() {
321 final StringBuilder sb = new StringBuilder();
322 final int N = mBuffer.size();
323 sb.append("Archive (");
324 sb.append(N);
325 sb.append(" notification");
326 sb.append((N==1)?")":"s)");
327 return sb.toString();
328 }
329
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500330 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700331 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500332 mBuffer.removeFirst();
333 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400334
335 // We don't want to store the heavy bits of the notification in the archive,
336 // but other clients in the system process might be using the object, so we
337 // store a (lightened) copy.
338 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500339 }
340
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500341 public Iterator<StatusBarNotification> descendingIterator() {
342 return mBuffer.descendingIterator();
343 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500344
345 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700346 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500347 final StatusBarNotification[] a
348 = new StatusBarNotification[Math.min(count, mBuffer.size())];
349 Iterator<StatusBarNotification> iter = descendingIterator();
350 int i=0;
351 while (iter.hasNext() && i < count) {
352 a[i++] = iter.next();
353 }
354 return a;
355 }
356
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500357 }
358
John Spurlock35ef0a62015-05-28 11:24:10 -0400359 private void readPolicyXml(InputStream stream, boolean forRestore)
360 throws XmlPullParserException, NumberFormatException, IOException {
361 final XmlPullParser parser = Xml.newPullParser();
362 parser.setInput(stream, StandardCharsets.UTF_8.name());
363
Chris Wrenacf424a2016-03-15 12:48:55 -0400364 while (parser.next() != END_DOCUMENT) {
John Spurlock35ef0a62015-05-28 11:24:10 -0400365 mZenModeHelper.readXml(parser, forRestore);
366 mRankingHelper.readXml(parser, forRestore);
367 }
368 }
369
John Spurlock056c5192014-04-20 21:52:01 -0400370 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400371 if (DBG) Slog.d(TAG, "loadPolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400372 synchronized(mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400373
John Spurlock056c5192014-04-20 21:52:01 -0400374 FileInputStream infile = null;
375 try {
376 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400377 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400378 } catch (FileNotFoundException e) {
379 // No data yet
380 } catch (IOException e) {
381 Log.wtf(TAG, "Unable to read notification policy", e);
382 } catch (NumberFormatException e) {
383 Log.wtf(TAG, "Unable to parse notification policy", e);
384 } catch (XmlPullParserException e) {
385 Log.wtf(TAG, "Unable to parse notification policy", e);
386 } finally {
387 IoUtils.closeQuietly(infile);
388 }
389 }
390 }
391
392 public void savePolicyFile() {
393 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
394 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
395 }
396
397 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400398 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400399 synchronized (mPolicyFile) {
400 final FileOutputStream stream;
401 try {
402 stream = mPolicyFile.startWrite();
403 } catch (IOException e) {
404 Slog.w(TAG, "Failed to save policy file", e);
405 return;
406 }
407
408 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400409 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400410 mPolicyFile.finishWrite(stream);
411 } catch (IOException e) {
412 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
413 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400414 }
415 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400416 BackupManager.dataChanged(getContext().getPackageName());
417 }
418
419 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
420 final XmlSerializer out = new FastXmlSerializer();
421 out.setOutput(stream, StandardCharsets.UTF_8.name());
422 out.startDocument(null, true);
423 out.startTag(null, TAG_NOTIFICATION_POLICY);
424 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
425 mZenModeHelper.writeXml(out, forBackup);
426 mRankingHelper.writeXml(out, forBackup);
427 out.endTag(null, TAG_NOTIFICATION_POLICY);
428 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400429 }
430
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500431 /** Use this when you actually want to post a notification or toast.
432 *
433 * Unchecked. Not exposed via Binder, but can be called in the course of enqueue*().
434 */
435 private boolean noteNotificationOp(String pkg, int uid) {
436 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
437 != AppOpsManager.MODE_ALLOWED) {
438 Slog.v(TAG, "notifications are disabled by AppOps for " + pkg);
439 return false;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400440 }
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500441 return true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400442 }
443
Chris Wren66189fc2015-06-25 14:04:33 -0400444 /** Use this to check if a package can post a notification or toast. */
445 private boolean checkNotificationOp(String pkg, int uid) {
446 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000447 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
Chris Wren66189fc2015-06-25 14:04:33 -0400448 }
449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 private static final class ToastRecord
451 {
452 final int pid;
453 final String pkg;
454 final ITransientNotification callback;
455 int duration;
Svet Ganovb3b22cb2016-07-14 16:08:09 -0700456 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457
Svet Ganovb3b22cb2016-07-14 16:08:09 -0700458 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
459 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 this.pid = pid;
461 this.pkg = pkg;
462 this.callback = callback;
463 this.duration = duration;
Svet Ganovb3b22cb2016-07-14 16:08:09 -0700464 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 }
466
467 void update(int duration) {
468 this.duration = duration;
469 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800470
John Spurlock25e2d242014-06-27 13:58:23 -0400471 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
472 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 pw.println(prefix + this);
474 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 @Override
477 public final String toString()
478 {
479 return "ToastRecord{"
480 + Integer.toHexString(System.identityHashCode(this))
481 + " pkg=" + pkg
482 + " callback=" + callback
483 + " duration=" + duration;
484 }
485 }
486
Adam Lesinski182f73f2013-12-05 16:48:06 -0800487 private final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800488
Adam Lesinski182f73f2013-12-05 16:48:06 -0800489 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 public void onSetDisabled(int status) {
491 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400492 mDisableNotificationEffects =
493 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400494 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 // cancel whatever's going on
496 long identity = Binder.clearCallingIdentity();
497 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800498 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700499 if (player != null) {
500 player.stopAsync();
501 }
502 } catch (RemoteException e) {
503 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504 Binder.restoreCallingIdentity(identity);
505 }
506
507 identity = Binder.clearCallingIdentity();
508 try {
509 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700510 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 Binder.restoreCallingIdentity(identity);
512 }
513 }
514 }
515 }
516
Adam Lesinski182f73f2013-12-05 16:48:06 -0800517 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400518 public void onClearAll(int callingUid, int callingPid, int userId) {
Adam Lesinskie8240262014-03-26 16:01:00 -0700519 synchronized (mNotificationList) {
Kenny Guya263e4e2014-03-03 18:24:03 +0000520 cancelAllLocked(callingUid, callingPid, userId, REASON_DELEGATE_CANCEL_ALL, null,
521 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 }
524
Adam Lesinski182f73f2013-12-05 16:48:06 -0800525 @Override
Christoph Studer03b87a22014-04-30 17:33:27 +0200526 public void onNotificationClick(int callingUid, int callingPid, String key) {
527 synchronized (mNotificationList) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200528 NotificationRecord r = mNotificationsByKey.get(key);
529 if (r == null) {
530 Log.w(TAG, "No notification with key: " + key);
531 return;
532 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400533 final long now = System.currentTimeMillis();
534 EventLogTags.writeNotificationClicked(key,
535 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
536
Christoph Studer03b87a22014-04-30 17:33:27 +0200537 StatusBarNotification sbn = r.sbn;
538 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
539 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
540 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
541 REASON_DELEGATE_CLICK, null);
542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 }
544
Adam Lesinski182f73f2013-12-05 16:48:06 -0800545 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200546 public void onNotificationActionClick(int callingUid, int callingPid, String key,
547 int actionIndex) {
548 synchronized (mNotificationList) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200549 NotificationRecord r = mNotificationsByKey.get(key);
550 if (r == null) {
551 Log.w(TAG, "No notification with key: " + key);
552 return;
553 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400554 final long now = System.currentTimeMillis();
555 EventLogTags.writeNotificationActionClicked(key, actionIndex,
556 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Christoph Studer4da84cd2014-10-21 17:24:20 +0200557 // TODO: Log action click via UsageStats.
558 }
559 }
560
561 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400562 public void onNotificationClear(int callingUid, int callingPid,
563 String pkg, String tag, int id, int userId) {
564 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000565 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
John Spurlocke6a7d932014-03-13 12:29:00 -0400566 true, userId, REASON_DELEGATE_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400567 }
568
Adam Lesinski182f73f2013-12-05 16:48:06 -0800569 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400570 public void onPanelRevealed(boolean clearEffects, int items) {
571 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100572 if (clearEffects) {
573 clearEffects();
574 }
575 }
576
577 @Override
578 public void onPanelHidden() {
579 EventLogTags.writeNotificationPanelHidden();
580 }
581
582 @Override
583 public void clearEffects() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 synchronized (mNotificationList) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100585 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400586 clearSoundLocked();
587 clearVibrateLocked();
588 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 }
590 }
Joe Onorato005847b2010-06-04 16:08:02 -0400591
Adam Lesinski182f73f2013-12-05 16:48:06 -0800592 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400593 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000594 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400595 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
596 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400597 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
598 REASON_DELEGATE_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700599 long ident = Binder.clearCallingIdentity();
600 try {
601 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
602 "Bad notification posted from package " + pkg
603 + ": " + message);
604 } catch (RemoteException e) {
605 }
606 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400607 }
John Spurlocke677d712014-02-13 12:52:19 -0500608
609 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400610 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
611 NotificationVisibility[] noLongerVisibleKeys) {
Christoph Studerffeb0c32014-05-07 22:23:56 +0200612 synchronized (mNotificationList) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400613 for (NotificationVisibility nv : newlyVisibleKeys) {
614 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200615 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400616 r.setVisibility(true, nv.rank);
617 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200618 }
619 // Note that we might receive this event after notifications
620 // have already left the system, e.g. after dismissing from the
621 // shade. Hence not finding notifications in
622 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400623 for (NotificationVisibility nv : noLongerVisibleKeys) {
624 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200625 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400626 r.setVisibility(false, nv.rank);
627 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200628 }
629 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200630 }
Chris Wren78403d72014-07-28 10:23:24 +0100631
632 @Override
633 public void onNotificationExpansionChanged(String key,
634 boolean userAction, boolean expanded) {
Chris Wren78403d72014-07-28 10:23:24 +0100635 synchronized (mNotificationList) {
636 NotificationRecord r = mNotificationsByKey.get(key);
637 if (r != null) {
638 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400639 final long now = System.currentTimeMillis();
640 EventLogTags.writeNotificationExpansion(key,
641 userAction ? 1 : 0, expanded ? 1 : 0,
642 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100643 }
644 }
645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 };
647
Chris Wren93bb8b82016-03-29 14:35:05 -0400648 private void clearSoundLocked() {
649 mSoundNotificationKey = null;
650 long identity = Binder.clearCallingIdentity();
651 try {
652 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
653 if (player != null) {
654 player.stopAsync();
655 }
656 } catch (RemoteException e) {
657 } finally {
658 Binder.restoreCallingIdentity(identity);
659 }
660 }
661
662 private void clearVibrateLocked() {
663 mVibrateNotificationKey = null;
664 long identity = Binder.clearCallingIdentity();
665 try {
666 mVibrator.cancel();
667 } finally {
668 Binder.restoreCallingIdentity(identity);
669 }
670 }
671
672 private void clearLightsLocked() {
673 // light
674 mLights.clear();
675 updateLightsLocked();
676 }
677
Kenny Guy70058402014-10-28 20:45:06 +0000678 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 @Override
680 public void onReceive(Context context, Intent intent) {
681 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -0800682 if (action == null) {
683 return;
684 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800686 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -0400687 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -0400688 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -0400689 boolean cancelNotifications = true;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000690 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -0400691
Chris Wren3da73022013-05-10 14:41:21 -0400692 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -0400693 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800694 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -0400695 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800696 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000697 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
698 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +0000699 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
700 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800701 String pkgList[] = null;
Chris Wrenae9bb572013-05-15 14:50:28 -0400702 boolean queryReplace = queryRemove &&
703 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
John Spurlocke77bb362014-04-26 10:24:59 -0400704 if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800705 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800706 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000707 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
708 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
709 reason = REASON_PACKAGE_SUSPENDED;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800710 } else if (queryRestart) {
711 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800712 } else {
713 Uri uri = intent.getData();
714 if (uri == null) {
715 return;
716 }
717 String pkgName = uri.getSchemeSpecificPart();
718 if (pkgName == null) {
719 return;
720 }
Daniel Sandler26ece572012-06-01 15:38:46 -0400721 if (packageChanged) {
722 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -0700723 try {
Kenny Guy70058402014-10-28 20:45:06 +0000724 final IPackageManager pm = AppGlobals.getPackageManager();
725 final int enabled = pm.getApplicationEnabledSetting(pkgName,
726 changeUserId != UserHandle.USER_ALL ? changeUserId :
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -0700727 UserHandle.USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -0700728 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
729 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
730 cancelNotifications = false;
731 }
732 } catch (IllegalArgumentException e) {
733 // Package doesn't exist; probably racing with uninstall.
734 // cancelNotifications is already true, so nothing to do here.
735 if (DBG) {
736 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
737 }
Kenny Guy70058402014-10-28 20:45:06 +0000738 } catch (RemoteException e) {
739 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -0400740 }
741 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800742 pkgList = new String[]{pkgName};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700744
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800745 if (pkgList != null && (pkgList.length > 0)) {
746 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -0400747 if (cancelNotifications) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400748 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500749 changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -0400750 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800751 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
John Spurlockb408e8e2014-04-23 21:12:45 -0400753 mListeners.onPackagesChanged(queryReplace, pkgList);
Chris Wrene0ba7eb2016-03-04 17:30:43 -0500754 mRankerServices.onPackagesChanged(queryReplace, pkgList);
John Spurlock7340fc82014-04-24 18:50:12 -0400755 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
John Spurlock35ef0a62015-05-28 11:24:10 -0400756 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
Kenny Guy70058402014-10-28 20:45:06 +0000757 }
758 }
759 };
760
761 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
762 @Override
763 public void onReceive(Context context, Intent intent) {
764 String action = intent.getAction();
765
766 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400767 // Keep track of screen on/off state, but do not turn off the notification light
768 // until user passes through the lock screen or views the notification.
769 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +0100770 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400771 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
772 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +0100773 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500774 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -0500775 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
776 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500777 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700778 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
779 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
780 if (userHandle >= 0) {
John Spurlocke6a7d932014-03-13 12:29:00 -0400781 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500782 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700783 }
Rubin Xue95057a2016-04-01 16:49:25 +0100784 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000785 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +0100786 if (userHandle >= 0) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000787 cancelAllNotificationsInt(MY_UID, MY_PID, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500788 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000789 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400790 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
791 // turn off LED when user passes through lock screen
792 mNotificationLight.turnOff();
Wei Liu97e56662016-03-04 10:52:33 -0800793 if (mStatusBar != null) {
794 mStatusBar.notificationLightOff();
795 }
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400796 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
John Spurlock1b8b22b2015-05-20 09:47:13 -0400797 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400798 // reload per-user settings
799 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -0400800 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200801 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -0400802 mConditionProviders.onUserSwitched(user);
803 mListeners.onUserSwitched(user);
Chris Wrene0ba7eb2016-03-04 17:30:43 -0500804 mRankerServices.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -0400805 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000806 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
John Spurlockb408e8e2014-04-23 21:12:45 -0400807 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -0400808 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
809 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
810 mZenModeHelper.onUserRemoved(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500811 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
812 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
813 mConditionProviders.onUserUnlocked(user);
814 mListeners.onUserUnlocked(user);
Chris Wrene0ba7eb2016-03-04 17:30:43 -0500815 mRankerServices.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500816 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 }
818 }
819 };
820
John Spurlock7c74f782015-06-04 13:01:42 -0400821 private final class SettingsObserver extends ContentObserver {
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400822 private final Uri NOTIFICATION_LIGHT_PULSE_URI
823 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wrend4054312016-06-24 17:07:40 -0400824 private final Uri NOTIFICATION_SOUND_URI
825 = Settings.System.getUriFor(Settings.System.NOTIFICATION_SOUND);
Chris Wren763a9bb2016-05-31 17:14:12 -0400826 private final Uri NOTIFICATION_RATE_LIMIT_URI
827 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400828
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700829 SettingsObserver(Handler handler) {
830 super(handler);
831 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800832
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700833 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800834 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400835 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700836 false, this, UserHandle.USER_ALL);
Chris Wrend4054312016-06-24 17:07:40 -0400837 resolver.registerContentObserver(NOTIFICATION_SOUND_URI,
838 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -0400839 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
840 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400841 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700842 }
843
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400844 @Override public void onChange(boolean selfChange, Uri uri) {
845 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700846 }
847
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400848 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800849 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400850 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
851 boolean pulseEnabled = Settings.System.getInt(resolver,
852 Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0;
853 if (mNotificationPulseEnabled != pulseEnabled) {
854 mNotificationPulseEnabled = pulseEnabled;
855 updateNotificationPulse();
856 }
857 }
Chris Wren763a9bb2016-05-31 17:14:12 -0400858 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
859 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
860 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
861 }
Chris Wrend4054312016-06-24 17:07:40 -0400862 if (uri == null || NOTIFICATION_SOUND_URI.equals(uri)) {
863 mSystemNotificationSound = Settings.System.getString(resolver,
864 Settings.System.NOTIFICATION_SOUND);
865 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700866 }
867 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500868
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400869 private SettingsObserver mSettingsObserver;
John Spurlock056c5192014-04-20 21:52:01 -0400870 private ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400871
John Spurlockcad57682014-07-26 17:09:56 -0400872 private final Runnable mBuzzBeepBlinked = new Runnable() {
873 @Override
874 public void run() {
Wei Liu97e56662016-03-04 10:52:33 -0800875 if (mStatusBar != null) {
876 mStatusBar.buzzBeepBlinked();
877 }
John Spurlockcad57682014-07-26 17:09:56 -0400878 }
879 };
880
Daniel Sandleredbb3802012-11-13 20:49:47 -0800881 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
882 int[] ar = r.getIntArray(resid);
883 if (ar == null) {
884 return def;
885 }
886 final int len = ar.length > maxlen ? maxlen : ar.length;
887 long[] out = new long[len];
888 for (int i=0; i<len; i++) {
889 out[i] = ar[i];
890 }
891 return out;
892 }
893
Jeff Brownb880d882014-02-10 19:47:07 -0800894 public NotificationManagerService(Context context) {
895 super(context);
896 }
897
Chris Wren93bb8b82016-03-29 14:35:05 -0400898 @VisibleForTesting
899 void setAudioManager(AudioManager audioMananger) {
900 mAudioManager = audioMananger;
901 }
902
903 @VisibleForTesting
904 void setVibrator(Vibrator vibrator) {
905 mVibrator = vibrator;
906 }
907
908 @VisibleForTesting
909 void setSystemReady(boolean systemReady) {
910 mSystemReady = systemReady;
911 }
912
913 @VisibleForTesting
914 void setHandler(Handler handler) {
915 mHandler = handler;
916 }
917
Chris Wrend4054312016-06-24 17:07:40 -0400918 @VisibleForTesting
919 void setSystemNotificationSound(String systemNotificationSound) {
920 mSystemNotificationSound = systemNotificationSound;
921 }
922
Adam Lesinski182f73f2013-12-05 16:48:06 -0800923 @Override
924 public void onStart() {
Chris Wren54bbef42014-07-09 18:37:56 -0400925 Resources resources = getContext().getResources();
926
Chris Wren763a9bb2016-05-31 17:14:12 -0400927 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
928 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
929 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
930
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 mAm = ActivityManagerNative.getDefault();
Adam Lesinski182f73f2013-12-05 16:48:06 -0800932 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
933 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700934 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
San Mehat3ee13172010-02-04 20:54:43 -0800935
Chris Wren0efdb882016-03-01 17:17:47 -0500936 // This is the package that contains the AOSP framework update.
937 mRankerServicePackageName = getContext().getPackageManager()
938 .getServicesSystemSharedLibraryPackageName();
939
Adam Lesinski182f73f2013-12-05 16:48:06 -0800940 mHandler = new WorkerHandler();
Chris Wrenf9536642014-04-17 10:01:54 -0400941 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -0400942 String[] extractorNames;
943 try {
944 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
945 } catch (Resources.NotFoundException e) {
946 extractorNames = new String[0];
947 }
Chris Wren5eab2b72015-06-16 13:56:22 -0400948 mUsageStats = new NotificationUsageStats(getContext());
Chris Wren51017d02015-12-15 15:34:46 -0500949 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Chris Wren54bbef42014-07-09 18:37:56 -0400950 mRankingHelper = new RankingHelper(getContext(),
Chris Wren51017d02015-12-15 15:34:46 -0500951 mRankingHandler,
Chris Wren5eab2b72015-06-16 13:56:22 -0400952 mUsageStats,
Chris Wren54bbef42014-07-09 18:37:56 -0400953 extractorNames);
John Spurlockb2278d62015-04-07 12:47:12 -0400954 mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
955 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -0400956 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -0400957 @Override
958 public void onConfigChanged() {
959 savePolicyFile();
960 }
John Spurlockd8afe3c2014-08-01 14:04:07 -0400961
962 @Override
963 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -0400964 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -0500965 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -0500966 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
967 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -0500968 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
John Spurlockd8afe3c2014-08-01 14:04:07 -0400969 synchronized(mNotificationList) {
Christoph Studer85a384b2014-08-27 20:16:15 +0200970 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400971 }
972 }
John Spurlock1fc476d2015-04-14 16:05:20 -0400973
974 @Override
975 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -0400976 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
977 }
John Spurlock056c5192014-04-20 21:52:01 -0400978 });
979 final File systemDir = new File(Environment.getDataDirectory(), "system");
980 mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500981
Chris Wrenacf424a2016-03-15 12:48:55 -0400982 syncBlockDb();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400983
Chris Wren0efdb882016-03-01 17:17:47 -0500984 // This is a MangedServices object that keeps track of the listeners.
John Spurlock7340fc82014-04-24 18:50:12 -0400985 mListeners = new NotificationListeners();
Chris Wren0efdb882016-03-01 17:17:47 -0500986
987 // This is a MangedServices object that keeps track of the ranker.
988 mRankerServices = new NotificationRankers();
989 // Find the updatable ranker and register it.
Julia Reynolds1c9bd422016-03-15 09:25:56 -0400990 mRankerServices.registerRanker();
Chris Wren0efdb882016-03-01 17:17:47 -0500991
Adam Lesinski182f73f2013-12-05 16:48:06 -0800992 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -0800993 if (mStatusBar != null) {
994 mStatusBar.setNotificationDelegate(mNotificationDelegate);
995 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996
Adam Lesinski182f73f2013-12-05 16:48:06 -0800997 final LightsManager lights = getLocalService(LightsManager.class);
998 mNotificationLight = lights.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
999 mAttentionLight = lights.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001000
Mike Lockwood670f9322010-01-20 12:13:36 -05001001 mDefaultNotificationColor = resources.getColor(
Scott Greenwald9a05b312013-06-28 00:37:54 -04001002 R.color.config_defaultNotificationColor);
Mike Lockwood670f9322010-01-20 12:13:36 -05001003 mDefaultNotificationLedOn = resources.getInteger(
Scott Greenwald9a05b312013-06-28 00:37:54 -04001004 R.integer.config_defaultNotificationLedOn);
Mike Lockwood670f9322010-01-20 12:13:36 -05001005 mDefaultNotificationLedOff = resources.getInteger(
Scott Greenwald9a05b312013-06-28 00:37:54 -04001006 R.integer.config_defaultNotificationLedOff);
Mike Lockwood670f9322010-01-20 12:13:36 -05001007
Daniel Sandleredbb3802012-11-13 20:49:47 -08001008 mDefaultVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001009 R.array.config_defaultNotificationVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001010 VIBRATE_PATTERN_MAXLEN,
1011 DEFAULT_VIBRATE_PATTERN);
1012
1013 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001014 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001015 VIBRATE_PATTERN_MAXLEN,
1016 DEFAULT_VIBRATE_PATTERN);
1017
Chris Wren5116a822014-06-04 15:59:50 -04001018 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1019
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001020 // Don't start allowing notifications until the setup wizard has run once.
1021 // After that, including subsequent boots, init with notifications turned on.
1022 // This works on the first boot because the setup wizard will toggle this
1023 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001024 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001025 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001026 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001027 }
John Spurlockb2278d62015-04-07 12:47:12 -04001028 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001029 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001030
John Spurlockb408e8e2014-04-23 21:12:45 -04001031 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001032 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001033
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001034 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001036 filter.addAction(Intent.ACTION_SCREEN_ON);
1037 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001038 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001039 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001040 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001041 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001042 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001043 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001044 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001045 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001046 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001047
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001048 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001049 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001050 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001051 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001052 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1053 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1054 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001055 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1056 null);
1057
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001058 IntentFilter suspendedPkgFilter = new IntentFilter();
1059 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1060 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1061 suspendedPkgFilter, null, null);
1062
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001063 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001064 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1065 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001066
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001067 mSettingsObserver = new SettingsObserver(mHandler);
Scott Greenwald9a05b312013-06-28 00:37:54 -04001068
Griff Hazen9f637d12014-06-10 11:13:51 -07001069 mArchive = new Archive(resources.getInteger(
1070 R.integer.config_notificationServiceArchiveSize));
1071
Adam Lesinski182f73f2013-12-05 16:48:06 -08001072 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1073 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 }
1075
John Spurlocke7a835b2015-05-13 10:47:05 -04001076 private void sendRegisteredOnlyBroadcast(String action) {
1077 getContext().sendBroadcastAsUser(new Intent(action)
1078 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1079 }
1080
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001081 /**
Chris Wrenacf424a2016-03-15 12:48:55 -04001082 * Make sure the XML config and the the AppOps system agree about blocks.
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001083 */
Chris Wrenacf424a2016-03-15 12:48:55 -04001084 private void syncBlockDb() {
John Spurlock056c5192014-04-20 21:52:01 -04001085 loadPolicyFile();
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001086
Chris Wrenacf424a2016-03-15 12:48:55 -04001087 // sync bans from ranker into app opps
1088 Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
1089 for(Entry<Integer, String> ban : packageBans.entrySet()) {
1090 final int uid = ban.getKey();
1091 final String packageName = ban.getValue();
1092 setNotificationsEnabledForPackageImpl(packageName, uid, false);
1093 }
1094
1095 // sync bans from app opps into ranker
1096 packageBans.clear();
1097 for (UserInfo user : UserManager.get(getContext()).getUsers()) {
1098 final int userId = user.getUserHandle().getIdentifier();
1099 final PackageManager packageManager = getContext().getPackageManager();
1100 List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
1101 final int packageCount = packages.size();
1102 for (int p = 0; p < packageCount; p++) {
1103 final String packageName = packages.get(p).packageName;
1104 try {
1105 final int uid = packageManager.getPackageUidAsUser(packageName, userId);
1106 if (!checkNotificationOp(packageName, uid)) {
1107 packageBans.put(uid, packageName);
1108 }
1109 } catch (NameNotFoundException e) {
1110 // forget you
1111 }
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001112 }
1113 }
Chris Wrenacf424a2016-03-15 12:48:55 -04001114 for (Entry<Integer, String> ban : packageBans.entrySet()) {
1115 mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
1116 }
1117
1118 savePolicyFile();
Daniel Sandler4a900ac2013-01-30 14:04:10 -05001119 }
1120
Adam Lesinski182f73f2013-12-05 16:48:06 -08001121 @Override
1122 public void onBootPhase(int phase) {
1123 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1124 // no beeping until we're basically done booting
1125 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001126
Adam Lesinski182f73f2013-12-05 16:48:06 -08001127 // Grab our optional AudioService
1128 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001129 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001130 mVrManagerInternal = getLocalService(VrManagerInternal.class);
Svet Ganovb3b22cb2016-07-14 16:08:09 -07001131 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001132 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001133 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1134 // This observer will force an update when observe is called, causing us to
1135 // bind to listener services.
1136 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001137 mListeners.onBootPhaseAppsCanStart();
Chris Wrene0ba7eb2016-03-04 17:30:43 -05001138 mRankerServices.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001139 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 }
1141 }
1142
Adam Lesinski182f73f2013-12-05 16:48:06 -08001143 void setNotificationsEnabledForPackageImpl(String pkg, int uid, boolean enabled) {
1144 Slog.v(TAG, (enabled?"en":"dis") + "abling notifications for " + pkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145
Adam Lesinski182f73f2013-12-05 16:48:06 -08001146 mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
1147 enabled ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148
Adam Lesinski182f73f2013-12-05 16:48:06 -08001149 // Now, cancel any outstanding notifications that are part of a just-disabled app
1150 if (ENABLE_BLOCKED_NOTIFICATIONS && !enabled) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001151 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, 0, 0, true, UserHandle.getUserId(uid),
Julia Reynoldsef37f282016-02-12 09:11:27 -05001152 REASON_PACKAGE_BANNED, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 }
1154 }
1155
John Spurlockd8afe3c2014-08-01 14:04:07 -04001156 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001157 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001158 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001159 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001160 mListenerHints = hints;
1161 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001162 }
1163
John Spurlockb4782522014-08-22 14:54:46 -04001164 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001165 final long updatedSuppressedEffects = calculateSuppressedEffects();
1166 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1167 final List<ComponentName> suppressors = getSuppressors();
1168 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1169 mEffectsSuppressors = suppressors;
1170 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001171 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001172 }
1173
Bryce Lee7219ada2016-04-08 10:54:23 -07001174 private ArrayList<ComponentName> getSuppressors() {
1175 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1176 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1177 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1178
1179 for (ManagedServiceInfo info : serviceInfoList) {
1180 names.add(info.component);
1181 }
1182 }
1183
1184 return names;
1185 }
1186
1187 private boolean removeDisabledHints(ManagedServiceInfo info) {
1188 return removeDisabledHints(info, 0);
1189 }
1190
1191 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1192 boolean removed = false;
1193
1194 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1195 final int hint = mListenersDisablingEffects.keyAt(i);
1196 final ArraySet<ManagedServiceInfo> listeners =
1197 mListenersDisablingEffects.valueAt(i);
1198
1199 if (hints == 0 || (hint & hints) == hint) {
1200 removed = removed || listeners.remove(info);
1201 }
1202 }
1203
1204 return removed;
1205 }
1206
1207 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1208 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1209 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1210 }
1211
1212 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1213 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1214 }
1215
1216 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1217 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1218 }
1219 }
1220
1221 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1222 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1223 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1224 }
1225
1226 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1227 hintListeners.add(info);
1228 }
1229
1230 private int calculateHints() {
1231 int hints = 0;
1232 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1233 int hint = mListenersDisablingEffects.keyAt(i);
1234 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1235
1236 if (!serviceInfoList.isEmpty()) {
1237 hints |= hint;
1238 }
1239 }
1240
1241 return hints;
1242 }
1243
1244 private long calculateSuppressedEffects() {
1245 int hints = calculateHints();
1246 long suppressedEffects = 0;
1247
1248 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1249 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1250 }
1251
1252 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1253 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1254 }
1255
1256 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1257 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1258 }
1259
1260 return suppressedEffects;
1261 }
1262
Christoph Studer85a384b2014-08-27 20:16:15 +02001263 private void updateInterruptionFilterLocked() {
1264 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1265 if (interruptionFilter == mInterruptionFilter) return;
1266 mInterruptionFilter = interruptionFilter;
1267 scheduleInterruptionFilterChanged(interruptionFilter);
1268 }
1269
Adam Lesinski182f73f2013-12-05 16:48:06 -08001270 private final IBinder mService = new INotificationManager.Stub() {
1271 // Toasts
1272 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001275 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001277 if (DBG) {
1278 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1279 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001281
1282 if (pkg == null || callback == null) {
1283 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1284 return ;
1285 }
1286
John Spurlock7340fc82014-04-24 18:50:12 -04001287 final boolean isSystemToast = isCallerSystem() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001288 final boolean isPackageSuspended =
1289 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001290
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001291 if (ENABLE_BLOCKED_TOASTS && (!noteNotificationOp(pkg, Binder.getCallingUid())
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001292 || isPackageSuspended)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001293 if (!isSystemToast) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001294 Slog.e(TAG, "Suppressing toast from package " + pkg
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001295 + (isPackageSuspended
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001296 ? " due to package suspended by administrator."
1297 : " by user request."));
Adam Lesinski182f73f2013-12-05 16:48:06 -08001298 return;
1299 }
1300 }
1301
1302 synchronized (mToastQueue) {
1303 int callingPid = Binder.getCallingPid();
1304 long callingId = Binder.clearCallingIdentity();
1305 try {
1306 ToastRecord record;
1307 int index = indexOfToastLocked(pkg, callback);
1308 // If it's already in the queue, we update it in place, we don't
1309 // move it to the end of the queue.
1310 if (index >= 0) {
1311 record = mToastQueue.get(index);
1312 record.update(duration);
1313 } else {
1314 // Limit the number of toasts that any given package except the android
1315 // package can enqueue. Prevents DOS attacks and deals with leaks.
1316 if (!isSystemToast) {
1317 int count = 0;
1318 final int N = mToastQueue.size();
1319 for (int i=0; i<N; i++) {
1320 final ToastRecord r = mToastQueue.get(i);
1321 if (r.pkg.equals(pkg)) {
1322 count++;
1323 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
1324 Slog.e(TAG, "Package has already posted " + count
1325 + " toasts. Not showing more. Package=" + pkg);
1326 return;
1327 }
1328 }
1329 }
1330 }
1331
Svet Ganovb3b22cb2016-07-14 16:08:09 -07001332 Binder token = new Binder();
1333 mWindowManagerInternal.addWindowToken(token,
1334 WindowManager.LayoutParams.TYPE_TOAST);
1335 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001336 mToastQueue.add(record);
1337 index = mToastQueue.size() - 1;
Svet Ganovb3b22cb2016-07-14 16:08:09 -07001338 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001339 }
1340 // If it's at index 0, it's the current toast. It doesn't matter if it's
1341 // new or just been updated. Call back and tell it to show itself.
1342 // If the callback fails, this will remove it from the list, so don't
1343 // assume that it's valid after this.
1344 if (index == 0) {
1345 showNextToastLocked();
1346 }
1347 } finally {
1348 Binder.restoreCallingIdentity(callingId);
1349 }
1350 }
1351 }
1352
1353 @Override
1354 public void cancelToast(String pkg, ITransientNotification callback) {
1355 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1356
1357 if (pkg == null || callback == null) {
1358 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1359 return ;
1360 }
1361
1362 synchronized (mToastQueue) {
1363 long callingId = Binder.clearCallingIdentity();
1364 try {
1365 int index = indexOfToastLocked(pkg, callback);
1366 if (index >= 0) {
1367 cancelToastLocked(index);
1368 } else {
1369 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1370 + " callback=" + callback);
1371 }
1372 } finally {
1373 Binder.restoreCallingIdentity(callingId);
1374 }
1375 }
1376 }
1377
1378 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001379 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Adam Lesinski182f73f2013-12-05 16:48:06 -08001380 Notification notification, int[] idOut, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001381 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Adam Lesinski182f73f2013-12-05 16:48:06 -08001382 Binder.getCallingPid(), tag, id, notification, idOut, userId);
1383 }
1384
1385 @Override
1386 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001387 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001388 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1389 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04001390 // Don't allow client applications to cancel foreground service notis or autobundled
1391 // summaries.
John Spurlocke6a7d932014-03-13 12:29:00 -04001392 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Julia Reynoldse46bb372016-03-17 11:05:58 -04001393 (Binder.getCallingUid() == Process.SYSTEM_UID
1394 ? 0 : Notification.FLAG_FOREGROUND_SERVICE)
1395 | (Binder.getCallingUid() == Process.SYSTEM_UID
1396 ? 0 : Notification.FLAG_AUTOGROUP_SUMMARY), false, userId,
Chris Wren9fa689f2015-11-20 16:44:53 -05001397 REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001398 }
1399
1400 @Override
1401 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001402 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001403
1404 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1405 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1406
1407 // Calling from user space, don't allow the canceling of actively
1408 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04001409 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
1410 pkg, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001411 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001412 }
1413
1414 @Override
1415 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
John Spurlock7340fc82014-04-24 18:50:12 -04001416 checkCallerIsSystem();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001417
1418 setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
Chris Wrenacf424a2016-03-15 12:48:55 -04001419 mRankingHelper.setEnabled(pkg, uid, enabled);
1420 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001421 }
1422
1423 /**
1424 * Use this when you just want to know if notifications are OK for this package.
1425 */
1426 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001427 public boolean areNotificationsEnabled(String pkg) {
1428 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1429 }
1430
1431 /**
1432 * Use this when you just want to know if notifications are OK for this package.
1433 */
1434 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001435 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001436 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001437 return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001438 == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001439 }
1440
Chris Wren54bbef42014-07-09 18:37:56 -04001441 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001442 public void setPriority(String pkg, int uid, int priority) {
Julia Reynoldsdd3e86b2016-02-02 10:24:30 -05001443 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001444 mRankingHelper.setPriority(pkg, uid, priority);
Chris Wren54bbef42014-07-09 18:37:56 -04001445 savePolicyFile();
1446 }
1447
1448 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001449 public int getPriority(String pkg, int uid) {
Chris Wren54bbef42014-07-09 18:37:56 -04001450 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001451 return mRankingHelper.getPriority(pkg, uid);
Chris Wren54bbef42014-07-09 18:37:56 -04001452 }
1453
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001454 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001455 public void setVisibilityOverride(String pkg, int uid, int visibility) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001456 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001457 mRankingHelper.setVisibilityOverride(pkg, uid, visibility);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001458 savePolicyFile();
1459 }
1460
1461 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001462 public int getVisibilityOverride(String pkg, int uid) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001463 checkCallerIsSystem();
Julia Reynoldsef37f282016-02-12 09:11:27 -05001464 return mRankingHelper.getVisibilityOverride(pkg, uid);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04001465 }
1466
Julia Reynolds5d25ee72015-11-20 15:38:20 -05001467 @Override
Julia Reynolds0edb50c2016-02-26 14:08:25 -05001468 public void setImportance(String pkg, int uid, int importance) {
Julia Reynoldsead00aa2015-12-07 08:23:48 -05001469 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynoldsef37f282016-02-12 09:11:27 -05001470 setNotificationsEnabledForPackageImpl(pkg, uid,
1471 importance != NotificationListenerService.Ranking.IMPORTANCE_NONE);
1472 mRankingHelper.setImportance(pkg, uid, importance);
Julia Reynolds5d25ee72015-11-20 15:38:20 -05001473 savePolicyFile();
1474 }
1475
1476 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001477 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001478 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05001479 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001480 }
1481
1482 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001483 public int getImportance(String pkg, int uid) {
Julia Reynoldscac88622016-03-03 09:28:19 -05001484 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynoldsef37f282016-02-12 09:11:27 -05001485 return mRankingHelper.getImportance(pkg, uid);
Julia Reynoldsbe8fdee2015-12-18 09:04:34 -05001486 }
1487
Adam Lesinski182f73f2013-12-05 16:48:06 -08001488 /**
1489 * System-only API for getting a list of current (i.e. not cleared) notifications.
1490 *
1491 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04001492 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001493 */
1494 @Override
1495 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1496 // enforce() will ensure the calling uid has the correct permission
1497 getContext().enforceCallingOrSelfPermission(
1498 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1499 "NotificationManagerService.getActiveNotifications");
1500
1501 StatusBarNotification[] tmp = null;
1502 int uid = Binder.getCallingUid();
1503
1504 // noteOp will check to make sure the callingPkg matches the uid
1505 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1506 == AppOpsManager.MODE_ALLOWED) {
1507 synchronized (mNotificationList) {
1508 tmp = new StatusBarNotification[mNotificationList.size()];
1509 final int N = mNotificationList.size();
1510 for (int i=0; i<N; i++) {
1511 tmp[i] = mNotificationList.get(i).sbn;
1512 }
1513 }
1514 }
1515 return tmp;
1516 }
1517
1518 /**
Dan Sandler994349c2015-04-15 11:02:54 -04001519 * Public API for getting a list of current notifications for the calling package/uid.
1520 *
1521 * @returns A list of all the package's notifications, in natural order.
1522 */
1523 @Override
1524 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1525 int incomingUserId) {
1526 checkCallerIsSystemOrSameApp(pkg);
1527 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1528 Binder.getCallingUid(), incomingUserId, true, false,
1529 "getAppActiveNotifications", pkg);
1530
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08001531 final ArrayList<StatusBarNotification> list
1532 = new ArrayList<StatusBarNotification>(mNotificationList.size());
Dan Sandler994349c2015-04-15 11:02:54 -04001533
1534 synchronized (mNotificationList) {
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08001535 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04001536 for (int i = 0; i < N; i++) {
1537 final StatusBarNotification sbn = mNotificationList.get(i).sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04001538 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId
1539 && (sbn.getNotification().flags
Julia Reynolds4c4ad592016-04-12 11:16:37 -04001540 & Notification.FLAG_AUTOGROUP_SUMMARY) == 0) {
Dan Sandler994349c2015-04-15 11:02:54 -04001541 // We could pass back a cloneLight() but clients might get confused and
1542 // try to send this thing back to notify() again, which would not work
1543 // very well.
1544 final StatusBarNotification sbnOut = new StatusBarNotification(
1545 sbn.getPackageName(),
1546 sbn.getOpPkg(),
1547 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
1548 0, // hide score from apps
1549 sbn.getNotification().clone(),
1550 sbn.getUser(), sbn.getPostTime());
1551 list.add(sbnOut);
1552 }
1553 }
1554 }
1555
1556 return new ParceledListSlice<StatusBarNotification>(list);
1557 }
1558
1559 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08001560 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
1561 *
1562 * Requires ACCESS_NOTIFICATIONS which is signature|system.
1563 */
1564 @Override
1565 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
1566 // enforce() will ensure the calling uid has the correct permission
1567 getContext().enforceCallingOrSelfPermission(
1568 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1569 "NotificationManagerService.getHistoricalNotifications");
1570
1571 StatusBarNotification[] tmp = null;
1572 int uid = Binder.getCallingUid();
1573
1574 // noteOp will check to make sure the callingPkg matches the uid
1575 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1576 == AppOpsManager.MODE_ALLOWED) {
1577 synchronized (mArchive) {
1578 tmp = mArchive.getArray(count);
1579 }
1580 }
1581 return tmp;
1582 }
1583
1584 /**
1585 * Register a listener binder directly with the notification manager.
1586 *
1587 * Only works with system callers. Apps should extend
1588 * {@link android.service.notification.NotificationListenerService}.
1589 */
1590 @Override
1591 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05001592 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02001593 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05001594 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001595 }
1596
1597 /**
1598 * Remove a listener binder directly
1599 */
1600 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05001601 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05001602 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001603 }
1604
1605 /**
1606 * Allow an INotificationListener to simulate a "clear all" operation.
1607 *
1608 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
1609 *
1610 * @param token The binder for the listener, to check that the caller is allowed
1611 */
1612 @Override
John Spurlocka4294292014-03-24 18:02:32 -04001613 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001614 final int callingUid = Binder.getCallingUid();
1615 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001616 long identity = Binder.clearCallingIdentity();
1617 try {
Adam Lesinskie8240262014-03-26 16:01:00 -07001618 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001619 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
John Spurlocka4294292014-03-24 18:02:32 -04001620 if (keys != null) {
1621 final int N = keys.length;
1622 for (int i = 0; i < N; i++) {
1623 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07001624 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00001625 final int userId = r.sbn.getUserId();
1626 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04001627 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00001628 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04001629 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00001630 }
Griff Hazen335e1f02014-09-11 14:49:31 -07001631 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1632 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
1633 userId);
John Spurlocka4294292014-03-24 18:02:32 -04001634 }
1635 } else {
1636 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00001637 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04001638 }
Adam Lesinskie8240262014-03-26 16:01:00 -07001639 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001640 } finally {
1641 Binder.restoreCallingIdentity(identity);
1642 }
1643 }
1644
Chris Wrenab41eec2016-01-04 18:01:27 -05001645 /**
1646 * Handle request from an approved listener to re-enable itself.
1647 *
1648 * @param component The componenet to be re-enabled, caller must match package.
1649 */
1650 @Override
1651 public void requestBindListener(ComponentName component) {
1652 checkCallerIsSystemOrSameApp(component.getPackageName());
1653 long identity = Binder.clearCallingIdentity();
1654 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04001655 ManagedServices manager =
1656 mRankerServices.isComponentEnabledForCurrentProfiles(component)
Chris Wrene0ba7eb2016-03-04 17:30:43 -05001657 ? mRankerServices
Chris Wrenab41eec2016-01-04 18:01:27 -05001658 : mListeners;
1659 manager.setComponentState(component, true);
1660 } finally {
1661 Binder.restoreCallingIdentity(identity);
1662 }
1663 }
1664
1665 @Override
1666 public void requestUnbindListener(INotificationListener token) {
1667 long identity = Binder.clearCallingIdentity();
1668 try {
1669 // allow bound services to disable themselves
1670 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1671 info.getOwner().setComponentState(info.component, false);
1672 } finally {
1673 Binder.restoreCallingIdentity(identity);
1674 }
1675 }
1676
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001677 @Override
1678 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001679 long identity = Binder.clearCallingIdentity();
1680 try {
1681 synchronized (mNotificationList) {
1682 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1683 if (keys != null) {
1684 final int N = keys.length;
1685 for (int i = 0; i < N; i++) {
1686 NotificationRecord r = mNotificationsByKey.get(keys[i]);
1687 if (r == null) continue;
1688 final int userId = r.sbn.getUserId();
1689 if (userId != info.userid && userId != UserHandle.USER_ALL &&
1690 !mUserProfiles.isCurrentProfile(userId)) {
1691 throw new SecurityException("Disallowed call from listener: "
1692 + info.service);
1693 }
1694 if (!r.isSeen()) {
1695 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
1696 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07001697 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001698 : userId,
Adam Lesinskic8e87292015-06-10 15:33:45 -07001699 UsageEvents.Event.USER_INTERACTION);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001700 r.setSeen();
1701 }
1702 }
1703 }
1704 }
1705 } finally {
1706 Binder.restoreCallingIdentity(identity);
1707 }
1708 }
1709
John Spurlock7340fc82014-04-24 18:50:12 -04001710 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00001711 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04001712 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
1713 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
1714 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00001715 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04001716 }
1717
Adam Lesinski182f73f2013-12-05 16:48:06 -08001718 /**
1719 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
1720 *
1721 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
1722 *
1723 * @param token The binder for the listener, to check that the caller is allowed
1724 */
1725 @Override
1726 public void cancelNotificationFromListener(INotificationListener token, String pkg,
1727 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04001728 final int callingUid = Binder.getCallingUid();
1729 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001730 long identity = Binder.clearCallingIdentity();
1731 try {
Adam Lesinskie8240262014-03-26 16:01:00 -07001732 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001733 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00001734 if (info.supportsProfiles()) {
1735 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
1736 + "from " + info.component
1737 + " use cancelNotification(key) instead.");
1738 } else {
1739 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
1740 pkg, tag, id, info.userid);
1741 }
Adam Lesinskie8240262014-03-26 16:01:00 -07001742 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001743 } finally {
1744 Binder.restoreCallingIdentity(identity);
1745 }
1746 }
1747
1748 /**
1749 * Allow an INotificationListener to request the list of outstanding notifications seen by
1750 * the current user. Useful when starting up, after which point the listener callbacks
1751 * should be used.
1752 *
1753 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001754 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04001755 * @returns The return value will contain the notifications specified in keys, in that
1756 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001757 */
1758 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02001759 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02001760 INotificationListener token, String[] keys, int trim) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001761 synchronized (mNotificationList) {
John Spurlock7340fc82014-04-24 18:50:12 -04001762 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001763 final boolean getKeys = keys != null;
1764 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02001765 final ArrayList<StatusBarNotification> list
1766 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02001767 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04001768 final NotificationRecord r = getKeys
1769 ? mNotificationsByKey.get(keys[i])
1770 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02001771 if (r == null) continue;
1772 StatusBarNotification sbn = r.sbn;
1773 if (!isVisibleToListener(sbn, info)) continue;
1774 StatusBarNotification sbnToSend =
1775 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
1776 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001777 }
Christoph Studercee44ba2014-05-20 18:36:43 +02001778 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001779 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001780 }
1781
1782 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04001783 public void requestHintsFromListener(INotificationListener token, int hints) {
1784 final long identity = Binder.clearCallingIdentity();
1785 try {
1786 synchronized (mNotificationList) {
1787 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07001788 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
1789 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
1790 | HINT_HOST_DISABLE_CALL_EFFECTS;
1791 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04001792 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07001793 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04001794 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07001795 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04001796 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001797 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04001798 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04001799 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001800 } finally {
1801 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04001802 }
1803 }
1804
1805 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04001806 public int getHintsFromListener(INotificationListener token) {
John Spurlock1fa865f2014-07-21 14:56:39 -04001807 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001808 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04001809 }
1810 }
1811
1812 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02001813 public void requestInterruptionFilterFromListener(INotificationListener token,
1814 int interruptionFilter) throws RemoteException {
1815 final long identity = Binder.clearCallingIdentity();
1816 try {
1817 synchronized (mNotificationList) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001818 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1819 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02001820 updateInterruptionFilterLocked();
1821 }
1822 } finally {
1823 Binder.restoreCallingIdentity(identity);
1824 }
1825 }
1826
1827 @Override
1828 public int getInterruptionFilterFromListener(INotificationListener token)
1829 throws RemoteException {
1830 synchronized (mNotificationLight) {
1831 return mInterruptionFilter;
1832 }
1833 }
1834
1835 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02001836 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
1837 throws RemoteException {
1838 synchronized (mNotificationList) {
1839 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
1840 if (info == null) return;
1841 mListeners.setOnNotificationPostedTrimLocked(info, trim);
1842 }
1843 }
1844
1845 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04001846 public int getZenMode() {
1847 return mZenModeHelper.getZenMode();
1848 }
1849
1850 @Override
John Spurlock056c5192014-04-20 21:52:01 -04001851 public ZenModeConfig getZenModeConfig() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001852 enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04001853 return mZenModeHelper.getConfig();
1854 }
1855
1856 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04001857 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001858 enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
1859 final long identity = Binder.clearCallingIdentity();
1860 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001861 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001862 } finally {
1863 Binder.restoreCallingIdentity(identity);
1864 }
1865 }
1866
1867 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05001868 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001869 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05001870 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001871 }
1872
1873 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001874 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
1875 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001876 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001877 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001878 }
1879
1880 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05001881 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001882 throws RemoteException {
1883 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1884 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1885 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1886 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001887 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001888
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001889 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
1890 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001891 }
1892
1893 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05001894 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001895 throws RemoteException {
1896 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
1897 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
1898 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
1899 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
1900 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001901
Julia Reynolds361e82d32016-02-26 18:19:49 -05001902 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001903 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001904 }
1905
1906 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001907 public boolean removeAutomaticZenRule(String id) throws RemoteException {
1908 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001909 // Verify that they can modify zen rules.
1910 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
1911
Julia Reynolds4fe98d62015-10-06 16:23:41 -04001912 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001913 }
1914
1915 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05001916 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
1917 Preconditions.checkNotNull(packageName, "Package name is null");
1918 enforceSystemOrSystemUI("removeAutomaticZenRules");
1919
1920 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
1921 }
1922
1923 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05001924 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
1925 Preconditions.checkNotNull(owner, "Owner is null");
1926 enforceSystemOrSystemUI("getRuleInstanceCount");
1927
1928 return mZenModeHelper.getCurrentInstanceCount(owner);
1929 }
1930
1931 @Override
John Spurlock80774932015-05-07 17:38:50 -04001932 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
1933 enforcePolicyAccess(pkg, "setInterruptionFilter");
1934 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
1935 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
1936 final long identity = Binder.clearCallingIdentity();
1937 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04001938 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04001939 } finally {
1940 Binder.restoreCallingIdentity(identity);
1941 }
1942 }
1943
1944 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04001945 public void notifyConditions(final String pkg, IConditionProvider provider,
1946 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04001947 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
1948 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04001949 mHandler.post(new Runnable() {
1950 @Override
1951 public void run() {
1952 mConditionProviders.notifyConditions(pkg, info, conditions);
1953 }
1954 });
John Spurlocke77bb362014-04-26 10:24:59 -04001955 }
1956
John Spurlockcdb57ae2015-02-11 19:04:11 -05001957 private void enforceSystemOrSystemUIOrVolume(String message) {
1958 if (mAudioManagerInternal != null) {
1959 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
1960 if (vcuid > 0 && Binder.getCallingUid() == vcuid) {
1961 return;
1962 }
1963 }
1964 enforceSystemOrSystemUI(message);
1965 }
1966
John Spurlocke77bb362014-04-26 10:24:59 -04001967 private void enforceSystemOrSystemUI(String message) {
1968 if (isCallerSystem()) return;
1969 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1970 message);
John Spurlock7340fc82014-04-24 18:50:12 -04001971 }
1972
Julia Reynolds48034f82016-03-09 10:15:16 -05001973 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
1974 try {
1975 checkCallerIsSystemOrSameApp(pkg);
1976 } catch (SecurityException e) {
1977 getContext().enforceCallingPermission(
1978 android.Manifest.permission.STATUS_BAR_SERVICE,
1979 message);
1980 }
1981 }
1982
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04001983 private void enforcePolicyAccess(int uid, String method) {
1984 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
1985 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
1986 return;
1987 }
1988 boolean accessAllowed = false;
1989 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
1990 final int packageCount = packages.length;
1991 for (int i = 0; i < packageCount; i++) {
1992 if (checkPolicyAccess(packages[i])) {
1993 accessAllowed = true;
1994 }
1995 }
1996 if (!accessAllowed) {
1997 Slog.w(TAG, "Notification policy access denied calling " + method);
1998 throw new SecurityException("Notification policy access denied");
1999 }
2000 }
2001
John Spurlock80774932015-05-07 17:38:50 -04002002 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04002003 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2004 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2005 return;
2006 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04002007 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002008 if (!checkPolicyAccess(pkg)) {
2009 Slog.w(TAG, "Notification policy access denied calling " + method);
2010 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04002011 }
2012 }
2013
John Spurlock80774932015-05-07 17:38:50 -04002014 private boolean checkPackagePolicyAccess(String pkg) {
John Spurlock7c74f782015-06-04 13:01:42 -04002015 return mPolicyAccess.isPackageGranted(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002016 }
2017
2018 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04002019 try {
2020 int uid = getContext().getPackageManager().getPackageUidAsUser(
2021 pkg, UserHandle.getCallingUserId());
2022 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2023 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2024 -1, true)) {
2025 return true;
2026 }
2027 } catch (NameNotFoundException e) {
2028 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002029 }
John Spurlock80774932015-05-07 17:38:50 -04002030 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002031 }
2032
John Spurlock7340fc82014-04-24 18:50:12 -04002033 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002034 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2035 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2036 != PackageManager.PERMISSION_GRANTED) {
John Spurlock2b122f42014-08-27 16:29:47 -04002037 pw.println("Permission Denial: can't dump NotificationManager from pid="
Adam Lesinski182f73f2013-12-05 16:48:06 -08002038 + Binder.getCallingPid()
2039 + ", uid=" + Binder.getCallingUid());
2040 return;
2041 }
2042
Chris Wrene4b38802015-07-07 15:54:19 -04002043 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2044 if (filter != null && filter.stats) {
2045 dumpJson(pw, filter);
2046 } else {
2047 dumpImpl(pw, filter);
2048 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002049 }
John Spurlockb4782522014-08-22 14:54:46 -04002050
2051 @Override
2052 public ComponentName getEffectsSuppressor() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002053 enforceSystemOrSystemUIOrVolume("INotificationManager.getEffectsSuppressor");
Bryce Leeba3d8952016-04-12 12:39:15 -07002054 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04002055 }
John Spurlock2b122f42014-08-27 16:29:47 -04002056
2057 @Override
2058 public boolean matchesCallFilter(Bundle extras) {
2059 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02002060 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002061 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02002062 extras,
2063 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2064 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2065 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04002066 }
John Spurlock530052a2014-11-30 16:26:19 -05002067
2068 @Override
2069 public boolean isSystemConditionProviderEnabled(String path) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002070 enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04002071 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05002072 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002073
Christopher Tatef9767d62015-04-08 14:35:43 -07002074 // Backup/restore interface
2075 @Override
2076 public byte[] getBackupPayload(int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002077 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002078 //TODO: http://b/22388012
2079 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002080 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2081 return null;
2082 }
2083 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2084 try {
2085 writePolicyXml(baos, true /*forBackup*/);
2086 return baos.toByteArray();
2087 } catch (IOException e) {
2088 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2089 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002090 return null;
2091 }
2092
2093 @Override
2094 public void applyRestore(byte[] payload, int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002095 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2096 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2097 if (payload == null) {
2098 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2099 return;
2100 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002101 //TODO: http://b/22388012
2102 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002103 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2104 return;
2105 }
2106 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2107 try {
2108 readPolicyXml(bais, true /*forRestore*/);
2109 savePolicyFile();
2110 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2111 Slog.w(TAG, "applyRestore: error reading payload", e);
2112 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002113 }
2114
John Spurlock1fc476d2015-04-14 16:05:20 -04002115 @Override
John Spurlock80774932015-05-07 17:38:50 -04002116 public boolean isNotificationPolicyAccessGranted(String pkg) {
2117 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002118 }
2119
2120 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05002121 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2122 enforceSystemOrSystemUIOrSamePackage(pkg,
2123 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002124 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002125 }
2126
2127 @Override
2128 public String[] getPackagesRequestingNotificationPolicyAccess()
2129 throws RemoteException {
2130 enforceSystemOrSystemUI("request policy access packages");
2131 final long identity = Binder.clearCallingIdentity();
2132 try {
John Spurlock7c74f782015-06-04 13:01:42 -04002133 return mPolicyAccess.getRequestingPackages();
John Spurlock80774932015-05-07 17:38:50 -04002134 } finally {
2135 Binder.restoreCallingIdentity(identity);
2136 }
2137 }
2138
2139 @Override
2140 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2141 throws RemoteException {
2142 enforceSystemOrSystemUI("grant notification policy access");
2143 final long identity = Binder.clearCallingIdentity();
2144 try {
2145 synchronized (mNotificationList) {
2146 mPolicyAccess.put(pkg, granted);
2147 }
2148 } finally {
2149 Binder.restoreCallingIdentity(identity);
2150 }
2151 }
2152
2153 @Override
2154 public Policy getNotificationPolicy(String pkg) {
2155 enforcePolicyAccess(pkg, "getNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002156 final long identity = Binder.clearCallingIdentity();
2157 try {
2158 return mZenModeHelper.getNotificationPolicy();
2159 } finally {
2160 Binder.restoreCallingIdentity(identity);
2161 }
2162 }
2163
2164 @Override
John Spurlock80774932015-05-07 17:38:50 -04002165 public void setNotificationPolicy(String pkg, Policy policy) {
2166 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002167 final long identity = Binder.clearCallingIdentity();
2168 try {
2169 mZenModeHelper.setNotificationPolicy(policy);
2170 } finally {
2171 Binder.restoreCallingIdentity(identity);
2172 }
2173 }
Chris Wren51017d02015-12-15 15:34:46 -05002174
2175 @Override
Julia Reynoldse46bb372016-03-17 11:05:58 -04002176 public void applyAdjustmentFromRankerService(INotificationListener token,
2177 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05002178 final long identity = Binder.clearCallingIdentity();
2179 try {
2180 synchronized (mNotificationList) {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002181 mRankerServices.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002182 applyAdjustmentLocked(adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05002183 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002184 maybeAddAutobundleSummary(adjustment);
2185 mRankingHandler.requestSort();
2186 } finally {
2187 Binder.restoreCallingIdentity(identity);
2188 }
2189 }
2190
2191 @Override
2192 public void applyAdjustmentsFromRankerService(INotificationListener token,
2193 List<Adjustment> adjustments) throws RemoteException {
2194
2195 final long identity = Binder.clearCallingIdentity();
2196 try {
2197 synchronized (mNotificationList) {
2198 mRankerServices.checkServiceTokenLocked(token);
2199 for (Adjustment adjustment : adjustments) {
2200 applyAdjustmentLocked(adjustment);
2201 }
2202 }
2203 for (Adjustment adjustment : adjustments) {
2204 maybeAddAutobundleSummary(adjustment);
2205 }
2206 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05002207 } finally {
2208 Binder.restoreCallingIdentity(identity);
2209 }
2210 }
John Spurlock1fc476d2015-04-14 16:05:20 -04002211 };
John Spurlocka4294292014-03-24 18:02:32 -04002212
Julia Reynoldse46bb372016-03-17 11:05:58 -04002213 private void applyAdjustmentLocked(Adjustment adjustment) {
2214 maybeClearAutobundleSummaryLocked(adjustment);
2215 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2216 if (n == null) {
2217 return;
2218 }
2219 if (adjustment.getImportance() != IMPORTANCE_NONE) {
2220 n.setImportance(adjustment.getImportance(), adjustment.getExplanation());
2221 }
2222 if (adjustment.getSignals() != null) {
2223 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldsb1ebc3b2016-04-15 15:12:36 -04002224 final String autoGroupKey = adjustment.getSignals().getString(
2225 Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2226 if (autoGroupKey == null) {
2227 EventLogTags.writeNotificationUnautogrouped(adjustment.getKey());
2228 } else {
2229 EventLogTags.writeNotificationAutogrouped(adjustment.getKey());
2230 }
2231 n.sbn.setOverrideGroupKey(autoGroupKey);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002232 }
2233 }
2234
2235 // Clears the 'fake' auto-bunding summary.
2236 private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002237 if (adjustment.getSignals() != null) {
2238 Bundle.setDefusable(adjustment.getSignals(), true);
2239 if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
Julia Reynoldse46bb372016-03-17 11:05:58 -04002240 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002241 ArrayMap<String, String> summaries =
2242 mAutobundledSummaries.get(adjustment.getUser());
2243 if (summaries != null && summaries.containsKey(adjustment.getPackage())) {
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002244 // Clear summary.
2245 final NotificationRecord removed = mNotificationsByKey.get(
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002246 summaries.remove(adjustment.getPackage()));
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002247 if (removed != null) {
2248 mNotificationList.remove(removed);
2249 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
2250 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002251 }
2252 }
2253 }
2254 }
2255
2256 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
2257 private void maybeAddAutobundleSummary(Adjustment adjustment) {
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002258 if (adjustment.getSignals() != null) {
2259 Bundle.setDefusable(adjustment.getSignals(), true);
2260 if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
2261 final String newAutoBundleKey =
2262 adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
2263 int userId = -1;
2264 NotificationRecord summaryRecord = null;
2265 synchronized (mNotificationList) {
Selim Cinek5b03ce92016-05-18 15:16:58 -07002266 NotificationRecord notificationRecord =
2267 mNotificationsByKey.get(adjustment.getKey());
2268 if (notificationRecord == null) {
2269 // The notification could have been cancelled again already. A successive
2270 // adjustment will post a summary if needed.
2271 return;
2272 }
2273 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002274 userId = adjustedSbn.getUser().getIdentifier();
2275 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
2276 if (summaries == null) {
2277 summaries = new ArrayMap<>();
2278 }
2279 mAutobundledSummaries.put(userId, summaries);
2280 if (!summaries.containsKey(adjustment.getPackage())
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002281 && newAutoBundleKey != null) {
2282 // Add summary
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002283 final ApplicationInfo appInfo =
2284 adjustedSbn.getNotification().extras.getParcelable(
2285 Notification.EXTRA_BUILDER_APPLICATION_INFO);
2286 final Bundle extras = new Bundle();
2287 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
2288 final Notification summaryNotification =
2289 new Notification.Builder(getContext()).setSmallIcon(
2290 adjustedSbn.getNotification().getSmallIcon())
2291 .setGroupSummary(true)
2292 .setGroup(newAutoBundleKey)
2293 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
2294 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
Julia Reynolds3011fd42016-05-20 10:25:43 -04002295 .setColor(adjustedSbn.getNotification().color)
Julia Reynolds29607002016-07-06 10:45:05 -04002296 .setLocalOnly(true)
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002297 .build();
2298 summaryNotification.extras.putAll(extras);
Julia Reynolds5bba3e72016-04-15 15:13:54 -04002299 Intent appIntent = getContext().getPackageManager()
2300 .getLaunchIntentForPackage(adjustment.getPackage());
2301 if (appIntent != null) {
2302 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
2303 getContext(), 0, appIntent, 0, null,
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002304 UserHandle.of(userId));
Julia Reynolds5bba3e72016-04-15 15:13:54 -04002305 }
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002306 final StatusBarNotification summarySbn =
2307 new StatusBarNotification(adjustedSbn.getPackageName(),
2308 adjustedSbn.getOpPkg(),
2309 Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
2310 adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
2311 summaryNotification, adjustedSbn.getUser(),
2312 newAutoBundleKey,
2313 System.currentTimeMillis());
2314 summaryRecord = new NotificationRecord(getContext(), summarySbn);
Julia Reynoldseae43fb2016-05-09 12:42:58 -04002315 summaries.put(adjustment.getPackage(), summarySbn.getKey());
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002316 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002317 }
Julia Reynoldsdbf44812016-04-14 08:54:45 -04002318 if (summaryRecord != null) {
2319 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
2320 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002321 }
2322 }
2323 }
2324
John Spurlock32fe4c62014-10-02 12:16:02 -04002325 private String disableNotificationEffects(NotificationRecord record) {
2326 if (mDisableNotificationEffects) {
2327 return "booleanState";
2328 }
2329 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2330 return "listenerHints";
2331 }
2332 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
2333 return "callState";
2334 }
2335 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04002336 };
2337
2338 private void dumpJson(PrintWriter pw, DumpFilter filter) {
2339 JSONObject dump = new JSONObject();
2340 try {
2341 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04002342 dump.put("bans", mRankingHelper.dumpBansJson(filter));
2343 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04002344 dump.put("stats", mUsageStats.dumpJson(filter));
2345 } catch (JSONException e) {
2346 e.printStackTrace();
2347 }
2348 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04002349 }
2350
John Spurlock25e2d242014-06-27 13:58:23 -04002351 void dumpImpl(PrintWriter pw, DumpFilter filter) {
2352 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04002353 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04002354 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04002355 }
2356 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08002357 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002358 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002359
John Spurlock50806fc2014-07-15 10:22:02 -04002360 if (!zenOnly) {
2361 synchronized (mToastQueue) {
2362 N = mToastQueue.size();
2363 if (N > 0) {
2364 pw.println(" Toast Queue:");
2365 for (int i=0; i<N; i++) {
2366 mToastQueue.get(i).dump(pw, " ", filter);
2367 }
2368 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002369 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002370 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002371 }
2372
2373 synchronized (mNotificationList) {
John Spurlock50806fc2014-07-15 10:22:02 -04002374 if (!zenOnly) {
2375 N = mNotificationList.size();
John Spurlock25e2d242014-06-27 13:58:23 -04002376 if (N > 0) {
John Spurlock50806fc2014-07-15 10:22:02 -04002377 pw.println(" Notification List:");
John Spurlock25e2d242014-06-27 13:58:23 -04002378 for (int i=0; i<N; i++) {
John Spurlock50806fc2014-07-15 10:22:02 -04002379 final NotificationRecord nr = mNotificationList.get(i);
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002380 if (filter.filtered && !filter.matches(nr.sbn)) continue;
Dan Sandlera1770312015-07-10 13:59:29 -04002381 nr.dump(pw, " ", getContext(), filter.redact);
John Spurlock25e2d242014-06-27 13:58:23 -04002382 }
2383 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002384 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002385
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002386 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04002387 N = mLights.size();
2388 if (N > 0) {
2389 pw.println(" Lights List:");
2390 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05002391 if (i == N - 1) {
2392 pw.print(" > ");
2393 } else {
2394 pw.print(" ");
2395 }
2396 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04002397 }
2398 pw.println(" ");
2399 }
John Spurlockcb566aa2014-08-03 22:58:28 -04002400 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
2401 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05002402 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
2403 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002404 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04002405 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04002406 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04002407 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04002408 }
2409 pw.println(" mArchive=" + mArchive.toString());
2410 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
2411 int i=0;
2412 while (iter.hasNext()) {
2413 final StatusBarNotification sbn = iter.next();
2414 if (filter != null && !filter.matches(sbn)) continue;
2415 pw.println(" " + sbn);
2416 if (++i >= 5) {
2417 if (iter.hasNext()) pw.println(" ...");
2418 break;
2419 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002420 }
2421 }
2422
John Spurlock50806fc2014-07-15 10:22:02 -04002423 if (!zenOnly) {
2424 pw.println("\n Usage Stats:");
2425 mUsageStats.dump(pw, " ", filter);
2426 }
Christoph Studer546bec82014-03-14 12:17:12 +01002427
Julia Reynoldse6b53e62015-07-31 09:25:10 -04002428 if (!filter.filtered || zenOnly) {
John Spurlock25e2d242014-06-27 13:58:23 -04002429 pw.println("\n Zen Mode:");
John Spurlockf3701772015-02-12 13:29:37 -05002430 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
John Spurlock25e2d242014-06-27 13:58:23 -04002431 mZenModeHelper.dump(pw, " ");
John Spurlock6ae82a72014-07-16 16:23:01 -04002432
2433 pw.println("\n Zen Log:");
2434 ZenLog.dump(pw, " ");
John Spurlock25e2d242014-06-27 13:58:23 -04002435 }
John Spurlocke77bb362014-04-26 10:24:59 -04002436
John Spurlock50806fc2014-07-15 10:22:02 -04002437 if (!zenOnly) {
2438 pw.println("\n Ranking Config:");
2439 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04002440
John Spurlock50806fc2014-07-15 10:22:02 -04002441 pw.println("\n Notification listeners:");
2442 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002443 pw.print(" mListenerHints: "); pw.println(mListenerHints);
2444 pw.print(" mListenersDisablingEffects: (");
2445 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04002446 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002447 final int hint = mListenersDisablingEffects.keyAt(i);
2448 if (i > 0) pw.print(';');
2449 pw.print("hint[" + hint + "]:");
2450
2451 final ArraySet<ManagedServiceInfo> listeners =
2452 mListenersDisablingEffects.valueAt(i);
2453 final int listenerSize = listeners.size();
2454
2455 for (int j = 0; j < listenerSize; j++) {
2456 if (i > 0) pw.print(',');
2457 final ManagedServiceInfo listener = listeners.valueAt(i);
2458 pw.print(listener.component);
2459 }
John Spurlock1fa865f2014-07-21 14:56:39 -04002460 }
2461 pw.println(')');
Chris Wren0efdb882016-03-01 17:17:47 -05002462 pw.println("\n mRankerServicePackageName: " + mRankerServicePackageName);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002463 pw.println("\n Notification ranker services:");
2464 mRankerServices.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04002465 }
John Spurlock80774932015-05-07 17:38:50 -04002466 pw.println("\n Policy access:");
2467 pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
John Spurlocke77bb362014-04-26 10:24:59 -04002468
2469 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04002470 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02002471
2472 pw.println("\n Group summaries:");
2473 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
2474 NotificationRecord r = entry.getValue();
2475 pw.println(" " + entry.getKey() + " -> " + r.getKey());
2476 if (mNotificationsByKey.get(r.getKey()) != r) {
2477 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04002478 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02002479 }
2480 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002481 }
2482 }
2483
Adam Lesinski182f73f2013-12-05 16:48:06 -08002484 /**
2485 * The private API only accessible to the system process.
2486 */
2487 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
2488 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002489 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002490 String tag, int id, Notification notification, int[] idReceived, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002491 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002492 idReceived, userId);
2493 }
Christoph Studer365e4c32014-09-18 20:35:36 +02002494
2495 @Override
2496 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
2497 int userId) {
2498 checkCallerIsSystem();
2499 synchronized (mNotificationList) {
2500 int i = indexOfNotificationLocked(pkg, null, notificationId, userId);
2501 if (i < 0) {
2502 Log.d(TAG, "stripForegroundServiceFlag: Could not find notification with "
2503 + "pkg=" + pkg + " / id=" + notificationId + " / userId=" + userId);
2504 return;
2505 }
2506 NotificationRecord r = mNotificationList.get(i);
2507 StatusBarNotification sbn = r.sbn;
2508 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
2509 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove FLAG_FOREGROUND_SERVICE,
2510 // we have to revert to the flags we received initially *and* force remove
2511 // FLAG_FOREGROUND_SERVICE.
2512 sbn.getNotification().flags =
2513 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
2514 mRankingHelper.sort(mNotificationList);
2515 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
2516 }
2517 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002518 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002519
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002520 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04002521 final int callingPid, final String tag, final int id, final Notification notification,
Adam Lesinski182f73f2013-12-05 16:48:06 -08002522 int[] idOut, int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04002523 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002524 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
2525 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04002526 }
John Spurlock7340fc82014-04-24 18:50:12 -04002527 checkCallerIsSystemOrSameApp(pkg);
2528 final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg));
Justin Koh38156c52014-06-04 13:57:49 -07002529 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08002530
Scott Greenwald9b05c612013-06-25 23:44:05 -04002531 final int userId = ActivityManager.handleIncomingUser(callingPid,
2532 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07002533 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07002534
Julia Reynoldse46bb372016-03-17 11:05:58 -04002535 // Fix the notification as best we can.
2536 try {
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06002537 final ApplicationInfo ai = getContext().getPackageManager().getApplicationInfoAsUser(
2538 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2539 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
2540 Notification.addFieldsFromContext(ai, userId, notification);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002541 } catch (NameNotFoundException e) {
2542 Slog.e(TAG, "Cannot create a context for sending app", e);
2543 return;
2544 }
2545
Chris Wren888b7a82016-06-17 15:47:19 -04002546 mUsageStats.registerEnqueuedByApp(pkg);
2547
Joe Onoratobd73d012010-06-04 11:44:54 -07002548 // Limit the number of notifications that any given package except the android
Justin Koh38156c52014-06-04 13:57:49 -07002549 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
2550 if (!isSystemNotification && !isNotificationFromListener) {
Joe Onoratobd73d012010-06-04 11:44:54 -07002551 synchronized (mNotificationList) {
Chris Wrenc8673a82016-05-17 17:11:29 -04002552 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
Chris Wren763a9bb2016-05-31 17:14:12 -04002553 if (appEnqueueRate > mMaxPackageEnqueueRate) {
Chris Wrenc8673a82016-05-17 17:11:29 -04002554 mUsageStats.registerOverRateQuota(pkg);
2555 final long now = SystemClock.elapsedRealtime();
2556 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
2557 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
2558 + ". Shedding events. package=" + pkg);
2559 mLastOverRateLogTime = now;
2560 }
2561 return;
2562 }
2563
Joe Onoratobd73d012010-06-04 11:44:54 -07002564 int count = 0;
2565 final int N = mNotificationList.size();
2566 for (int i=0; i<N; i++) {
2567 final NotificationRecord r = mNotificationList.get(i);
Daniel Sandler4f91efd2013-04-25 16:38:41 -04002568 if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) {
Vladimir Marko2526f332013-09-11 11:13:55 +01002569 if (r.sbn.getId() == id && TextUtils.equals(r.sbn.getTag(), tag)) {
2570 break; // Allow updating existing notification
2571 }
Joe Onoratobd73d012010-06-04 11:44:54 -07002572 count++;
2573 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
Chris Wrenc8673a82016-05-17 17:11:29 -04002574 mUsageStats.registerOverCountQuota(pkg);
Joe Onoratobd73d012010-06-04 11:44:54 -07002575 Slog.e(TAG, "Package has already posted " + count
2576 + " notifications. Not showing more. package=" + pkg);
2577 return;
2578 }
2579 }
2580 }
2581 }
2582 }
2583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002584 if (pkg == null || notification == null) {
2585 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
2586 + " id=" + id + " notification=" + notification);
2587 }
Dan Sandlerd63f9322015-05-06 15:18:49 -04002588
Felipe Lemedd85da62016-06-28 11:29:54 -07002589 // Whitelist pending intents.
2590 if (notification.allPendingIntents != null) {
2591 final int intentCount = notification.allPendingIntents.size();
2592 if (intentCount > 0) {
2593 final ActivityManagerInternal am = LocalServices
2594 .getService(ActivityManagerInternal.class);
2595 final long duration = LocalServices.getService(
2596 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
2597 for (int i = 0; i < intentCount; i++) {
2598 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
2599 if (pendingIntent != null) {
2600 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(), duration);
2601 }
2602 }
2603 }
2604 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07002605
Chris Wren47633422016-01-22 09:56:59 -05002606 // Sanitize inputs
2607 notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
2608 Notification.PRIORITY_MAX);
Daniel Sandler0da673f2012-04-11 12:33:16 -04002609
Chris Wren47633422016-01-22 09:56:59 -05002610 // setup local book-keeping
2611 final StatusBarNotification n = new StatusBarNotification(
2612 pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
2613 user);
2614 final NotificationRecord r = new NotificationRecord(getContext(), n);
2615 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616
2617 idOut[0] = id;
2618 }
2619
Chris Wren47633422016-01-22 09:56:59 -05002620 private class EnqueueNotificationRunnable implements Runnable {
2621 private final NotificationRecord r;
2622 private final int userId;
2623
2624 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
2625 this.userId = userId;
2626 this.r = r;
2627 };
2628
2629 @Override
2630 public void run() {
2631
2632 synchronized (mNotificationList) {
2633 final StatusBarNotification n = r.sbn;
Chris Wren1ac52a92016-02-24 14:54:52 -05002634 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
Chris Wren47633422016-01-22 09:56:59 -05002635 NotificationRecord old = mNotificationsByKey.get(n.getKey());
2636 if (old != null) {
2637 // Retain ranking information from previous record
2638 r.copyRankingInformation(old);
2639 }
2640
2641 final int callingUid = n.getUid();
2642 final int callingPid = n.getInitialPid();
2643 final Notification notification = n.getNotification();
2644 final String pkg = n.getPackageName();
2645 final int id = n.getId();
2646 final String tag = n.getTag();
2647 final boolean isSystemNotification = isUidSystem(callingUid) ||
2648 ("android".equals(pkg));
2649
2650 // Handle grouped notifications and bail out early if we
2651 // can to avoid extracting signals.
2652 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
Chris Wren47633422016-01-22 09:56:59 -05002653
2654 // This conditional is a dirty hack to limit the logging done on
2655 // behalf of the download manager without affecting other apps.
2656 if (!pkg.equals("com.android.providers.downloads")
2657 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
2658 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren8ab776c2016-04-11 16:48:24 -04002659 if (old != null) {
Chris Wren47633422016-01-22 09:56:59 -05002660 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
2661 }
2662 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
2663 pkg, id, tag, userId, notification.toString(),
2664 enqueueStatus);
2665 }
2666
Chris Wren47633422016-01-22 09:56:59 -05002667 mRankingHelper.extractSignals(r);
2668
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002669 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
Chris Wren47633422016-01-22 09:56:59 -05002670
Julia Reynoldsef37f282016-02-12 09:11:27 -05002671 // blocked apps
Chris Wren47633422016-01-22 09:56:59 -05002672 if (r.getImportance() == NotificationListenerService.Ranking.IMPORTANCE_NONE
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002673 || !noteNotificationOp(pkg, callingUid) || isPackageSuspended) {
Chris Wren47633422016-01-22 09:56:59 -05002674 if (!isSystemNotification) {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00002675 if (isPackageSuspended) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00002676 Slog.e(TAG, "Suppressing notification from package due to package "
2677 + "suspended by administrator.");
2678 mUsageStats.registerSuspendedByAdmin(r);
2679 } else {
2680 Slog.e(TAG, "Suppressing notification from package by user request.");
2681 mUsageStats.registerBlocked(r);
2682 }
Chris Wren47633422016-01-22 09:56:59 -05002683 return;
2684 }
2685 }
2686
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002687 // tell the ranker service about the notification
2688 if (mRankerServices.isEnabled()) {
2689 mRankerServices.onNotificationEnqueued(r);
Chris Wren47633422016-01-22 09:56:59 -05002690 // TODO delay the code below here for 100ms or until there is an answer
2691 }
2692
2693
2694 int index = indexOfNotificationLocked(n.getKey());
2695 if (index < 0) {
2696 mNotificationList.add(r);
2697 mUsageStats.registerPostedByApp(r);
2698 } else {
2699 old = mNotificationList.get(index);
2700 mNotificationList.set(index, r);
2701 mUsageStats.registerUpdatedByApp(r, old);
2702 // Make sure we don't lose the foreground service state.
2703 notification.flags |=
2704 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
2705 r.isUpdate = true;
2706 }
2707
2708 mNotificationsByKey.put(n.getKey(), r);
2709
2710 // Ensure if this is a foreground service that the proper additional
2711 // flags are set.
2712 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
2713 notification.flags |= Notification.FLAG_ONGOING_EVENT
2714 | Notification.FLAG_NO_CLEAR;
2715 }
2716
2717 applyZenModeLocked(r);
2718 mRankingHelper.sort(mNotificationList);
2719
2720 if (notification.getSmallIcon() != null) {
2721 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
2722 mListeners.notifyPostedLocked(n, oldSbn);
2723 } else {
2724 Slog.e(TAG, "Not posting notification without small icon: " + notification);
2725 if (old != null && !old.isCanceled) {
2726 mListeners.notifyRemovedLocked(n);
2727 }
2728 // ATTENTION: in a future release we will bail out here
2729 // so that we do not play sounds, show lights, etc. for invalid
2730 // notifications
2731 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
2732 + n.getPackageName());
2733 }
2734
2735 buzzBeepBlinkLocked(r);
2736 }
2737 }
2738 }
2739
Christoph Studer265c1052014-07-23 17:14:33 +02002740 /**
2741 * Ensures that grouped notification receive their special treatment.
2742 *
2743 * <p>Cancels group children if the new notification causes a group to lose
2744 * its summary.</p>
2745 *
2746 * <p>Updates mSummaryByGroupKey.</p>
2747 */
2748 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
2749 int callingUid, int callingPid) {
2750 StatusBarNotification sbn = r.sbn;
2751 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07002752 if (n.isGroupSummary() && !sbn.isAppGroup()) {
2753 // notifications without a group shouldn't be a summary, otherwise autobundling can
2754 // lead to bugs
2755 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
2756 }
2757
Christoph Studer265c1052014-07-23 17:14:33 +02002758 String group = sbn.getGroupKey();
2759 boolean isSummary = n.isGroupSummary();
2760
2761 Notification oldN = old != null ? old.sbn.getNotification() : null;
2762 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
2763 boolean oldIsSummary = old != null && oldN.isGroupSummary();
2764
2765 if (oldIsSummary) {
2766 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
2767 if (removedSummary != old) {
2768 String removedKey =
2769 removedSummary != null ? removedSummary.getKey() : "<null>";
2770 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
2771 ", removed=" + removedKey);
2772 }
2773 }
2774 if (isSummary) {
2775 mSummaryByGroupKey.put(group, r);
2776 }
2777
2778 // Clear out group children of the old notification if the update
2779 // causes the group summary to go away. This happens when the old
2780 // notification was a summary and the new one isn't, or when the old
2781 // notification was a summary and its group key changed.
2782 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
2783 cancelGroupChildrenLocked(old, callingUid, callingPid, null,
Selim Cinekce87a8a2016-06-20 15:40:07 -07002784 REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
Christoph Studer265c1052014-07-23 17:14:33 +02002785 }
2786 }
2787
Chris Wren93bb8b82016-03-29 14:35:05 -04002788 @VisibleForTesting
2789 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04002790 boolean buzz = false;
2791 boolean beep = false;
2792 boolean blink = false;
2793
Chris Wrena3446562014-06-03 18:11:47 -04002794 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04002795 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04002796
2797 // Should this notification make noise, vibe, or use the LED?
Julia Reynoldsf0f629f2016-02-25 09:34:04 -05002798 final boolean aboveThreshold = record.getImportance() >= IMPORTANCE_DEFAULT;
Chris Wrence00a232014-11-21 16:25:19 -05002799 final boolean canInterrupt = aboveThreshold && !record.isIntercepted();
Chris Wrena3446562014-06-03 18:11:47 -04002800 if (DBG || record.isIntercepted())
2801 Slog.v(TAG,
2802 "pkg=" + record.sbn.getPackageName() + " canInterrupt=" + canInterrupt +
2803 " intercept=" + record.isIntercepted()
2804 );
2805
2806 final int currentUser;
2807 final long token = Binder.clearCallingIdentity();
2808 try {
2809 currentUser = ActivityManager.getCurrentUser();
2810 } finally {
2811 Binder.restoreCallingIdentity(token);
2812 }
2813
2814 // If we're not supposed to beep, vibrate, etc. then don't.
John Spurlock32fe4c62014-10-02 12:16:02 -04002815 final String disableEffects = disableNotificationEffects(record);
2816 if (disableEffects != null) {
2817 ZenLog.traceDisableEffects(record, disableEffects);
2818 }
Chris Wren93bb8b82016-03-29 14:35:05 -04002819
2820 // Remember if this notification already owns the notification channels.
2821 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
2822 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
2823
2824 // These are set inside the conditional if the notification is allowed to make noise.
2825 boolean hasValidVibrate = false;
2826 boolean hasValidSound = false;
John Spurlock32fe4c62014-10-02 12:16:02 -04002827 if (disableEffects == null
Chris Wrena3446562014-06-03 18:11:47 -04002828 && (record.getUserId() == UserHandle.USER_ALL ||
2829 record.getUserId() == currentUser ||
2830 mUserProfiles.isCurrentProfile(record.getUserId()))
2831 && canInterrupt
2832 && mSystemReady
2833 && mAudioManager != null) {
2834 if (DBG) Slog.v(TAG, "Interrupting!");
2835
Chris Wrena3446562014-06-03 18:11:47 -04002836 // should we use the default notification sound? (indicated either by
2837 // DEFAULT_SOUND or because notification.sound is pointing at
2838 // Settings.System.NOTIFICATION_SOUND)
2839 final boolean useDefaultSound =
2840 (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
2841 Settings.System.DEFAULT_NOTIFICATION_URI
2842 .equals(notification.sound);
2843
2844 Uri soundUri = null;
Chris Wrena3446562014-06-03 18:11:47 -04002845 if (useDefaultSound) {
2846 soundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
2847
2848 // check to see if the default notification sound is silent
Chris Wrend4054312016-06-24 17:07:40 -04002849 hasValidSound = mSystemNotificationSound != null;
Chris Wrena3446562014-06-03 18:11:47 -04002850 } else if (notification.sound != null) {
2851 soundUri = notification.sound;
2852 hasValidSound = (soundUri != null);
2853 }
2854
Chris Wrena3446562014-06-03 18:11:47 -04002855 // Does the notification want to specify its own vibration?
2856 final boolean hasCustomVibrate = notification.vibrate != null;
2857
2858 // new in 4.2: if there was supposed to be a sound and we're in vibrate
2859 // mode, and no other vibration is specified, we fall back to vibration
2860 final boolean convertSoundToVibration =
Chris Wren93bb8b82016-03-29 14:35:05 -04002861 !hasCustomVibrate
2862 && hasValidSound
2863 && (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE);
Chris Wrena3446562014-06-03 18:11:47 -04002864
2865 // The DEFAULT_VIBRATE flag trumps any custom vibration AND the fallback.
2866 final boolean useDefaultVibrate =
2867 (notification.defaults & Notification.DEFAULT_VIBRATE) != 0;
2868
Chris Wren93bb8b82016-03-29 14:35:05 -04002869 hasValidVibrate = useDefaultVibrate || convertSoundToVibration ||
2870 hasCustomVibrate;
Chris Wrena3446562014-06-03 18:11:47 -04002871
Chris Wren93bb8b82016-03-29 14:35:05 -04002872 // We can alert, and we're allowed to alert, but if the developer asked us to only do
2873 // it once, and we already have, then don't.
2874 if (!(record.isUpdate
2875 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
2876
2877 sendAccessibilityEvent(notification, record.sbn.getPackageName());
2878
2879 if (hasValidSound) {
2880 boolean looping =
2881 (notification.flags & Notification.FLAG_INSISTENT) != 0;
2882 AudioAttributes audioAttributes = audioAttributesForNotification(notification);
2883 mSoundNotificationKey = key;
2884 // do not play notifications if stream volume is 0 (typically because
2885 // ringer mode is silent) or if there is a user of exclusive audio focus
2886 if ((mAudioManager.getStreamVolume(
2887 AudioAttributes.toLegacyStreamType(audioAttributes)) != 0)
2888 && !mAudioManager.isAudioFocusExclusive()) {
2889 final long identity = Binder.clearCallingIdentity();
2890 try {
2891 final IRingtonePlayer player =
2892 mAudioManager.getRingtonePlayer();
2893 if (player != null) {
2894 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
2895 + " with attributes " + audioAttributes);
2896 player.playAsync(soundUri, record.sbn.getUser(), looping,
2897 audioAttributes);
2898 beep = true;
2899 }
2900 } catch (RemoteException e) {
2901 } finally {
2902 Binder.restoreCallingIdentity(identity);
2903 }
Chris Wrena3446562014-06-03 18:11:47 -04002904 }
Chris Wren93bb8b82016-03-29 14:35:05 -04002905 }
2906
2907 if (hasValidVibrate && !(mAudioManager.getRingerModeInternal()
2908 == AudioManager.RINGER_MODE_SILENT)) {
2909 mVibrateNotificationKey = key;
2910
2911 if (useDefaultVibrate || convertSoundToVibration) {
2912 // Escalate privileges so we can use the vibrator even if the
2913 // notifying app does not have the VIBRATE permission.
2914 long identity = Binder.clearCallingIdentity();
2915 try {
2916 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2917 useDefaultVibrate ? mDefaultVibrationPattern
2918 : mFallbackVibrationPattern,
2919 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2920 ? 0: -1, audioAttributesForNotification(notification));
2921 buzz = true;
2922 } finally {
2923 Binder.restoreCallingIdentity(identity);
2924 }
2925 } else if (notification.vibrate.length > 1) {
2926 // If you want your own vibration pattern, you need the VIBRATE
2927 // permission
2928 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
2929 notification.vibrate,
2930 ((notification.flags & Notification.FLAG_INSISTENT) != 0)
2931 ? 0: -1, audioAttributesForNotification(notification));
2932 buzz = true;
2933 }
Chris Wrena3446562014-06-03 18:11:47 -04002934 }
2935 }
Chris Wren93bb8b82016-03-29 14:35:05 -04002936
2937 }
2938 // If a notification is updated to remove the actively playing sound or vibrate,
2939 // cancel that feedback now
2940 if (wasBeep && !hasValidSound) {
2941 clearSoundLocked();
2942 }
2943 if (wasBuzz && !hasValidVibrate) {
2944 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04002945 }
2946
2947 // light
2948 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04002949 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05002950 if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
2951 && ((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05002952 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04002953 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04002954 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04002955 if (mUseAttentionLight) {
2956 mAttentionLight.pulse();
2957 }
Chris Wren82ba59d2015-06-05 11:23:44 -04002958 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04002959 } else if (wasShowLights) {
2960 updateLightsLocked();
2961 }
Chris Wren82ba59d2015-06-05 11:23:44 -04002962 if (buzz || beep || blink) {
Julia Reynolds61721582016-01-05 08:35:25 -05002963 if (((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05002964 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) != 0)) {
Julia Reynolds61721582016-01-05 08:35:25 -05002965 if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
2966 } else {
Chris Wren93bb8b82016-03-29 14:35:05 -04002967 EventLogTags.writeNotificationAlert(key,
Julia Reynolds61721582016-01-05 08:35:25 -05002968 buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
2969 mHandler.post(mBuzzBeepBlinked);
2970 }
John Spurlockcad57682014-07-26 17:09:56 -04002971 }
Chris Wrena3446562014-06-03 18:11:47 -04002972 }
2973
John Spurlock7b414672014-07-18 13:02:39 -04002974 private static AudioAttributes audioAttributesForNotification(Notification n) {
Marco Nelissen1c066302014-11-18 10:48:12 -08002975 if (n.audioAttributes != null
2976 && !Notification.AUDIO_ATTRIBUTES_DEFAULT.equals(n.audioAttributes)) {
2977 // the audio attributes are set and different from the default, use them
John Spurlockbfa5dc42014-07-28 23:30:45 -04002978 return n.audioAttributes;
Jean-Michel Triviceb79bc2014-09-05 11:09:14 -07002979 } else if (n.audioStreamType >= 0 && n.audioStreamType < AudioSystem.getNumStreamTypes()) {
2980 // the stream type is valid, use it
2981 return new AudioAttributes.Builder()
2982 .setInternalLegacyStreamType(n.audioStreamType)
2983 .build();
2984 } else if (n.audioStreamType == AudioSystem.STREAM_DEFAULT) {
2985 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
2986 } else {
2987 Log.w(TAG, String.format("Invalid stream type: %d", n.audioStreamType));
2988 return Notification.AUDIO_ATTRIBUTES_DEFAULT;
John Spurlockbfa5dc42014-07-28 23:30:45 -04002989 }
John Spurlock7b414672014-07-18 13:02:39 -04002990 }
2991
Adam Lesinski182f73f2013-12-05 16:48:06 -08002992 void showNextToastLocked() {
2993 ToastRecord record = mToastQueue.get(0);
2994 while (record != null) {
2995 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
2996 try {
Svet Ganovb3b22cb2016-07-14 16:08:09 -07002997 record.callback.show(record.token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002998 scheduleTimeoutLocked(record);
2999 return;
3000 } catch (RemoteException e) {
3001 Slog.w(TAG, "Object died trying to show notification " + record.callback
3002 + " in package " + record.pkg);
3003 // remove it from the list and let the process die
3004 int index = mToastQueue.indexOf(record);
3005 if (index >= 0) {
3006 mToastQueue.remove(index);
3007 }
Svet Ganovb3b22cb2016-07-14 16:08:09 -07003008 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003009 if (mToastQueue.size() > 0) {
3010 record = mToastQueue.get(0);
3011 } else {
3012 record = null;
3013 }
3014 }
3015 }
3016 }
3017
3018 void cancelToastLocked(int index) {
3019 ToastRecord record = mToastQueue.get(index);
3020 try {
3021 record.callback.hide();
3022 } catch (RemoteException e) {
3023 Slog.w(TAG, "Object died trying to hide notification " + record.callback
3024 + " in package " + record.pkg);
3025 // don't worry about this, we're about to remove it from
3026 // the list anyway
3027 }
Svet Ganovb3b22cb2016-07-14 16:08:09 -07003028
3029 ToastRecord lastToast = mToastQueue.remove(index);
3030 mWindowManagerInternal.removeWindowToken(lastToast.token, true);
3031
3032 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003033 if (mToastQueue.size() > 0) {
3034 // Show the next one. If the callback fails, this will remove
3035 // it from the list, so don't assume that the list hasn't changed
3036 // after this point.
3037 showNextToastLocked();
3038 }
3039 }
3040
3041 private void scheduleTimeoutLocked(ToastRecord r)
3042 {
3043 mHandler.removeCallbacksAndMessages(r);
3044 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
3045 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
3046 mHandler.sendMessageDelayed(m, delay);
3047 }
3048
3049 private void handleTimeout(ToastRecord record)
3050 {
3051 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
3052 synchronized (mToastQueue) {
3053 int index = indexOfToastLocked(record.pkg, record.callback);
3054 if (index >= 0) {
3055 cancelToastLocked(index);
3056 }
3057 }
3058 }
3059
3060 // lock on mToastQueue
3061 int indexOfToastLocked(String pkg, ITransientNotification callback)
3062 {
3063 IBinder cbak = callback.asBinder();
3064 ArrayList<ToastRecord> list = mToastQueue;
3065 int len = list.size();
3066 for (int i=0; i<len; i++) {
3067 ToastRecord r = list.get(i);
3068 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
3069 return i;
3070 }
3071 }
3072 return -1;
3073 }
3074
3075 // lock on mToastQueue
Svet Ganovb3b22cb2016-07-14 16:08:09 -07003076 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08003077 {
3078 int toastCount = 0; // toasts from this pid
3079 ArrayList<ToastRecord> list = mToastQueue;
3080 int N = list.size();
3081 for (int i=0; i<N; i++) {
3082 ToastRecord r = list.get(i);
3083 if (r.pid == pid) {
3084 toastCount++;
3085 }
3086 }
3087 try {
3088 mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
3089 } catch (RemoteException e) {
3090 // Shouldn't happen.
3091 }
3092 }
3093
Chris Wrenf9536642014-04-17 10:01:54 -04003094 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04003095 if (!(message.obj instanceof RankingReconsideration)) return;
3096 RankingReconsideration recon = (RankingReconsideration) message.obj;
3097 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04003098 boolean changed;
Chris Wren470c1ac2014-05-21 15:28:10 -04003099 synchronized (mNotificationList) {
3100 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
3101 if (record == null) {
3102 return;
Chris Wrenf9536642014-04-17 10:01:54 -04003103 }
Chris Wren333a61c2014-05-28 16:40:57 -04003104 int indexBefore = findNotificationRecordIndexLocked(record);
3105 boolean interceptBefore = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003106 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04003107 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04003108 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04003109 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04003110 int indexAfter = findNotificationRecordIndexLocked(record);
3111 boolean interceptAfter = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003112 int visibilityAfter = record.getPackageVisibilityOverride();
3113 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
3114 || visibilityBefore != visibilityAfter;
Chris Wrena3446562014-06-03 18:11:47 -04003115 if (interceptBefore && !interceptAfter) {
3116 buzzBeepBlinkLocked(record);
3117 }
Chris Wrenf9536642014-04-17 10:01:54 -04003118 }
Chris Wren333a61c2014-05-28 16:40:57 -04003119 if (changed) {
Chris Wren470c1ac2014-05-21 15:28:10 -04003120 scheduleSendRankingUpdate();
3121 }
3122 }
3123
Chris Wren51017d02015-12-15 15:34:46 -05003124 private void handleRankingSort() {
Chris Wren54bbef42014-07-09 18:37:56 -04003125 synchronized (mNotificationList) {
3126 final int N = mNotificationList.size();
3127 ArrayList<String> orderBefore = new ArrayList<String>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003128 ArrayList<String> groupOverrideBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003129 int[] visibilities = new int[N];
Julia Reynoldse46bb372016-03-17 11:05:58 -04003130 int[] importances = new int[N];
Chris Wren54bbef42014-07-09 18:37:56 -04003131 for (int i = 0; i < N; i++) {
3132 final NotificationRecord r = mNotificationList.get(i);
3133 orderBefore.add(r.getKey());
Julia Reynoldse46bb372016-03-17 11:05:58 -04003134 groupOverrideBefore.add(r.sbn.getGroupKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003135 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds69766692016-02-01 15:35:08 -05003136 importances[i] = r.getImportance();
Chris Wren54bbef42014-07-09 18:37:56 -04003137 mRankingHelper.extractSignals(r);
3138 }
Chris Wren19a02b02015-12-22 10:34:22 -05003139 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04003140 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003141 final NotificationRecord r = mNotificationList.get(i);
3142 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05003143 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldse46bb372016-03-17 11:05:58 -04003144 || importances[i] != r.getImportance()
3145 || !groupOverrideBefore.get(i).equals(r.sbn.getGroupKey())) {
Chris Wren54bbef42014-07-09 18:37:56 -04003146 scheduleSendRankingUpdate();
3147 return;
3148 }
3149 }
3150 }
3151 }
3152
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04003153 private void recordCallerLocked(NotificationRecord record) {
3154 if (mZenModeHelper.isCall(record)) {
3155 mZenModeHelper.recordCaller(record);
3156 }
3157 }
3158
Christoph Studerd5092bc2014-07-03 17:47:58 +02003159 // let zen mode evaluate this record
Chris Wren333a61c2014-05-28 16:40:57 -04003160 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02003161 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003162 if (record.isIntercepted()) {
Julia Reynoldsd5607292016-02-05 15:25:58 -05003163 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
3164 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
3165 | (mZenModeHelper.shouldSuppressWhenScreenOn()
3166 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003167 record.setSuppressedVisualEffects(suppressed);
3168 }
Chris Wren333a61c2014-05-28 16:40:57 -04003169 }
3170
Chris Wren470c1ac2014-05-21 15:28:10 -04003171 // lock on mNotificationList
3172 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04003173 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04003174 }
3175
3176 private void scheduleSendRankingUpdate() {
Chris Wren52020492016-04-06 11:12:02 -04003177 if (!mHandler.hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
3178 Message m = Message.obtain(mHandler, MESSAGE_SEND_RANKING_UPDATE);
3179 mHandler.sendMessage(m);
3180 }
Chris Wrenf9536642014-04-17 10:01:54 -04003181 }
3182
3183 private void handleSendRankingUpdate() {
3184 synchronized (mNotificationList) {
Chris Wren333a61c2014-05-28 16:40:57 -04003185 mListeners.notifyRankingUpdateLocked();
Chris Wrenf9536642014-04-17 10:01:54 -04003186 }
3187 }
3188
John Spurlockd8afe3c2014-08-01 14:04:07 -04003189 private void scheduleListenerHintsChanged(int state) {
3190 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
3191 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04003192 }
3193
Christoph Studer85a384b2014-08-27 20:16:15 +02003194 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
3195 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
3196 mHandler.obtainMessage(
3197 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
3198 listenerInterruptionFilter,
3199 0).sendToTarget();
3200 }
3201
John Spurlockd8afe3c2014-08-01 14:04:07 -04003202 private void handleListenerHintsChanged(int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04003203 synchronized (mNotificationList) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003204 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04003205 }
3206 }
3207
Christoph Studer85a384b2014-08-27 20:16:15 +02003208 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
3209 synchronized (mNotificationList) {
3210 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
3211 }
3212 }
3213
Adam Lesinski182f73f2013-12-05 16:48:06 -08003214 private final class WorkerHandler extends Handler
3215 {
3216 @Override
3217 public void handleMessage(Message msg)
3218 {
3219 switch (msg.what)
3220 {
3221 case MESSAGE_TIMEOUT:
3222 handleTimeout((ToastRecord)msg.obj);
3223 break;
John Spurlock056c5192014-04-20 21:52:01 -04003224 case MESSAGE_SAVE_POLICY_FILE:
3225 handleSavePolicyFile();
3226 break;
Chris Wrenf9536642014-04-17 10:01:54 -04003227 case MESSAGE_SEND_RANKING_UPDATE:
3228 handleSendRankingUpdate();
3229 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04003230 case MESSAGE_LISTENER_HINTS_CHANGED:
3231 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04003232 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02003233 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
3234 handleListenerInterruptionFilterChanged(msg.arg1);
3235 break;
Chris Wrenf9536642014-04-17 10:01:54 -04003236 }
3237 }
3238
3239 }
3240
Chris Wren51017d02015-12-15 15:34:46 -05003241 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04003242 {
Chris Wren51017d02015-12-15 15:34:46 -05003243 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04003244 super(looper);
3245 }
3246
3247 @Override
3248 public void handleMessage(Message msg) {
3249 switch (msg.what) {
3250 case MESSAGE_RECONSIDER_RANKING:
3251 handleRankingReconsideration(msg);
3252 break;
Chris Wren51017d02015-12-15 15:34:46 -05003253 case MESSAGE_RANKING_SORT:
3254 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04003255 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003256 }
3257 }
Chris Wren51017d02015-12-15 15:34:46 -05003258
3259 public void requestSort() {
3260 removeMessages(MESSAGE_RANKING_SORT);
3261 sendEmptyMessage(MESSAGE_RANKING_SORT);
3262 }
3263
3264 public void requestReconsideration(RankingReconsideration recon) {
3265 Message m = Message.obtain(this,
3266 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
3267 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
3268 sendMessageDelayed(m, delay);
3269 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003270 }
3271
Adam Lesinski182f73f2013-12-05 16:48:06 -08003272 // Notifications
3273 // ============================================================================
3274 static int clamp(int x, int low, int high) {
3275 return (x < low) ? low : ((x > high) ? high : x);
3276 }
3277
3278 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
3279 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
svetoslavganov75986cf2009-05-14 22:28:01 -07003280 if (!manager.isEnabled()) {
3281 return;
3282 }
3283
3284 AccessibilityEvent event =
3285 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
3286 event.setPackageName(packageName);
3287 event.setClassName(Notification.class.getName());
3288 event.setParcelableData(notification);
3289 CharSequence tickerText = notification.tickerText;
3290 if (!TextUtils.isEmpty(tickerText)) {
3291 event.getText().add(tickerText);
3292 }
3293
3294 manager.sendAccessibilityEvent(event);
3295 }
3296
Christoph Studer546bec82014-03-14 12:17:12 +01003297 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason) {
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04003298
3299 // Record caller.
3300 recordCallerLocked(r);
3301
Joe Onorato46439ce2010-11-19 13:56:21 -08003302 // tell the app
3303 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003304 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08003305 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003306 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08003307 } catch (PendingIntent.CanceledException ex) {
3308 // do nothing - there's no relevant way to recover, and
3309 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04003310 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08003311 }
3312 }
3313 }
3314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 // status bar
Dan Sandlerd63f9322015-05-06 15:18:49 -04003316 if (r.getNotification().getSmallIcon() != null) {
Christoph Studer71f18fd2014-05-20 17:02:04 +02003317 r.isCanceled = true;
Chris Wren333a61c2014-05-28 16:40:57 -04003318 mListeners.notifyRemovedLocked(r.sbn);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 }
3320
Chris Wren6054e612014-11-25 17:16:46 -05003321 final String canceledKey = r.getKey();
3322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003323 // sound
Chris Wren6054e612014-11-25 17:16:46 -05003324 if (canceledKey.equals(mSoundNotificationKey)) {
3325 mSoundNotificationKey = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -07003326 final long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003328 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07003329 if (player != null) {
3330 player.stopAsync();
3331 }
3332 } catch (RemoteException e) {
3333 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 Binder.restoreCallingIdentity(identity);
3335 }
3336 }
3337
3338 // vibrate
Chris Wren6054e612014-11-25 17:16:46 -05003339 if (canceledKey.equals(mVibrateNotificationKey)) {
3340 mVibrateNotificationKey = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341 long identity = Binder.clearCallingIdentity();
3342 try {
3343 mVibrator.cancel();
3344 }
3345 finally {
3346 Binder.restoreCallingIdentity(identity);
3347 }
3348 }
3349
3350 // light
Chris Wren6054e612014-11-25 17:16:46 -05003351 mLights.remove(canceledKey);
Daniel Sandler23d7c702013-03-07 16:32:06 -05003352
Christoph Studer546bec82014-03-14 12:17:12 +01003353 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04003354 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01003355 switch (reason) {
3356 case REASON_DELEGATE_CANCEL:
3357 case REASON_DELEGATE_CANCEL_ALL:
3358 case REASON_LISTENER_CANCEL:
3359 case REASON_LISTENER_CANCEL_ALL:
3360 mUsageStats.registerDismissedByUser(r);
3361 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05003362 case REASON_APP_CANCEL:
3363 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01003364 mUsageStats.registerRemovedByApp(r);
3365 break;
Christoph Studer546bec82014-03-14 12:17:12 +01003366 }
3367
Christoph Studercef37cf2014-07-25 14:18:17 +02003368 mNotificationsByKey.remove(r.sbn.getKey());
Christoph Studer265c1052014-07-23 17:14:33 +02003369 String groupKey = r.getGroupKey();
3370 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
3371 if (groupSummary != null && groupSummary.getKey().equals(r.getKey())) {
3372 mSummaryByGroupKey.remove(groupKey);
3373 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04003374 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
3375 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
3376 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04003377 }
Christoph Studercef37cf2014-07-25 14:18:17 +02003378
Daniel Sandler23d7c702013-03-07 16:32:06 -05003379 // Save it for users of getHistoricalNotifications()
3380 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02003381
Chris Wren6650e572015-05-15 17:19:25 -04003382 final long now = System.currentTimeMillis();
Chris Wrene6ddb8a2015-05-27 15:21:00 -04003383 EventLogTags.writeNotificationCanceled(canceledKey, reason,
3384 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 }
3386
3387 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07003388 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003389 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003390 */
John Spurlocke6a7d932014-03-13 12:29:00 -04003391 void cancelNotification(final int callingUid, final int callingPid,
3392 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003393 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04003394 final int userId, final int reason, final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003395 // In enqueueNotificationInternal notifications are added by scheduling the
3396 // work on the worker handler. Hence, we also schedule the cancel on this
3397 // handler to avoid a scenario where an add notification call followed by a
3398 // remove notification call ends up in not removing the notification.
3399 mHandler.post(new Runnable() {
3400 @Override
3401 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003402 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08003403 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
3404 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003406 synchronized (mNotificationList) {
3407 int index = indexOfNotificationLocked(pkg, tag, id, userId);
3408 if (index >= 0) {
3409 NotificationRecord r = mNotificationList.get(index);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003410
Christoph Studer546bec82014-03-14 12:17:12 +01003411 // Ideally we'd do this in the caller of this method. However, that would
3412 // require the caller to also find the notification.
3413 if (reason == REASON_DELEGATE_CLICK) {
3414 mUsageStats.registerClickedByUser(r);
3415 }
3416
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003417 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
3418 return;
3419 }
3420 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
3421 return;
3422 }
3423
3424 mNotificationList.remove(index);
3425
Selim Cinek3f19f602016-05-02 18:01:56 -07003426 cancelNotificationLocked(r, sendDelete, reason);
Christoph Studer265c1052014-07-23 17:14:33 +02003427 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003428 REASON_GROUP_SUMMARY_CANCELED, sendDelete);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003429 updateLightsLocked();
3430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003432 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07003433 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003434 }
3435
3436 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07003437 * Determine whether the userId applies to the notification in question, either because
3438 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
3439 */
3440 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
3441 return
3442 // looking for USER_ALL notifications? match everything
3443 userId == UserHandle.USER_ALL
3444 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003445 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07003446 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003447 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07003448 }
3449
3450 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003451 * Determine whether the userId applies to the notification in question, either because
3452 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01003453 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003454 */
Kenny Guy2a764942014-04-02 13:29:20 +01003455 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00003456 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04003457 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00003458 }
3459
3460 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05003461 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 * {@code mustHaveFlags}.
3463 */
John Spurlocke6a7d932014-03-13 12:29:00 -04003464 boolean cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, int mustHaveFlags,
Julia Reynoldsef37f282016-02-12 09:11:27 -05003465 int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04003466 ManagedServiceInfo listener) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003467 String listenerName = listener == null ? null : listener.component.toShortString();
John Spurlocke6a7d932014-03-13 12:29:00 -04003468 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
3469 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
Christoph Studere4ef156b2014-07-04 18:41:57 +02003470 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003471
3472 synchronized (mNotificationList) {
3473 final int N = mNotificationList.size();
Christoph Studere4ef156b2014-07-04 18:41:57 +02003474 ArrayList<NotificationRecord> canceledNotifications = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003475 for (int i = N-1; i >= 0; --i) {
3476 NotificationRecord r = mNotificationList.get(i);
Daniel Sandler321e9c52012-10-12 10:59:26 -07003477 if (!notificationMatchesUserId(r, userId)) {
Dianne Hackborn41203752012-08-31 14:05:51 -07003478 continue;
3479 }
Amith Yamasani5ec00e92012-11-07 16:58:30 -08003480 // Don't remove notifications to all, if there's no package name specified
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003481 if (r.getUserId() == UserHandle.USER_ALL && pkg == null) {
Amith Yamasani5ec00e92012-11-07 16:58:30 -08003482 continue;
3483 }
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003484 if ((r.getFlags() & mustHaveFlags) != mustHaveFlags) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485 continue;
3486 }
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003487 if ((r.getFlags() & mustNotHaveFlags) != 0) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07003488 continue;
3489 }
Daniel Sandler4f91efd2013-04-25 16:38:41 -04003490 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003491 continue;
3492 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003493 if (canceledNotifications == null) {
3494 canceledNotifications = new ArrayList<>();
3495 }
3496 canceledNotifications.add(r);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08003497 if (!doit) {
3498 return true;
3499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500 mNotificationList.remove(i);
Christoph Studer546bec82014-03-14 12:17:12 +01003501 cancelNotificationLocked(r, false, reason);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003502 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003503 if (doit && canceledNotifications != null) {
3504 final int M = canceledNotifications.size();
3505 for (int i = 0; i < M; i++) {
3506 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003507 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003508 }
3509 }
3510 if (canceledNotifications != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003511 updateLightsLocked();
3512 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003513 return canceledNotifications != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003514 }
3515 }
3516
Adam Lesinski350159c2014-03-27 11:15:11 -07003517 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04003518 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003519 String listenerName = listener == null ? null : listener.component.toShortString();
John Spurlocke6a7d932014-03-13 12:29:00 -04003520 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
Christoph Studere4ef156b2014-07-04 18:41:57 +02003521 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01003522
Christoph Studere4ef156b2014-07-04 18:41:57 +02003523 ArrayList<NotificationRecord> canceledNotifications = null;
Adam Lesinskie8240262014-03-26 16:01:00 -07003524 final int N = mNotificationList.size();
3525 for (int i=N-1; i>=0; i--) {
3526 NotificationRecord r = mNotificationList.get(i);
Kenny Guya263e4e2014-03-03 18:24:03 +00003527 if (includeCurrentProfiles) {
3528 if (!notificationMatchesCurrentProfiles(r, userId)) {
3529 continue;
3530 }
3531 } else {
3532 if (!notificationMatchesUserId(r, userId)) {
3533 continue;
3534 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 }
3536
Adam Lesinskie8240262014-03-26 16:01:00 -07003537 if ((r.getFlags() & (Notification.FLAG_ONGOING_EVENT
3538 | Notification.FLAG_NO_CLEAR)) == 0) {
3539 mNotificationList.remove(i);
Christoph Studer546bec82014-03-14 12:17:12 +01003540 cancelNotificationLocked(r, true, reason);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003541 // Make a note so we can cancel children later.
3542 if (canceledNotifications == null) {
3543 canceledNotifications = new ArrayList<>();
3544 }
3545 canceledNotifications.add(r);
Adam Lesinskie8240262014-03-26 16:01:00 -07003546 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 }
Christoph Studere4ef156b2014-07-04 18:41:57 +02003548 int M = canceledNotifications != null ? canceledNotifications.size() : 0;
3549 for (int i = 0; i < M; i++) {
3550 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003551 listenerName, REASON_GROUP_SUMMARY_CANCELED, false /* sendDelete */);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003552 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003553 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003554 }
3555
Christoph Studere4ef156b2014-07-04 18:41:57 +02003556 // Warning: The caller is responsible for invoking updateLightsLocked().
3557 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Selim Cinekce87a8a2016-06-20 15:40:07 -07003558 String listenerName, int reason, boolean sendDelete) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003559 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02003560 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02003561 return;
3562 }
3563
3564 String pkg = r.sbn.getPackageName();
3565 int userId = r.getUserId();
3566
3567 if (pkg == null) {
3568 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
3569 return;
3570 }
3571
3572 final int N = mNotificationList.size();
3573 for (int i = N - 1; i >= 0; i--) {
3574 NotificationRecord childR = mNotificationList.get(i);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003575 StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003576 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Christoph Studerc44caa92014-08-22 19:16:00 +02003577 childR.getGroupKey().equals(r.getGroupKey())) {
Christoph Studer265c1052014-07-23 17:14:33 +02003578 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
3579 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003580 mNotificationList.remove(i);
Selim Cinekce87a8a2016-06-20 15:40:07 -07003581 cancelNotificationLocked(childR, sendDelete, reason);
Christoph Studere4ef156b2014-07-04 18:41:57 +02003582 }
3583 }
3584 }
3585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003586 // lock on mNotificationList
Adam Lesinski182f73f2013-12-05 16:48:06 -08003587 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588 {
The Android Open Source Project10592532009-03-18 17:39:46 -07003589 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05003590 NotificationRecord ledNotification = null;
3591 while (ledNotification == null && !mLights.isEmpty()) {
3592 final String owner = mLights.get(mLights.size() - 1);
3593 ledNotification = mNotificationsByKey.get(owner);
3594 if (ledNotification == null) {
3595 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
3596 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 }
3598 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05003599
Mike Lockwood63b5ad92011-08-30 09:55:30 -04003600 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05003601 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05003602 mNotificationLight.turnOff();
Wei Liu97e56662016-03-04 10:52:33 -08003603 if (mStatusBar != null) {
3604 mStatusBar.notificationLightOff();
3605 }
The Android Open Source Project10592532009-03-18 17:39:46 -07003606 } else {
Chris Wren6054e612014-11-25 17:16:46 -05003607 final Notification ledno = ledNotification.sbn.getNotification();
Daniel Sandlerfde19b12013-01-17 00:21:05 -05003608 int ledARGB = ledno.ledARGB;
3609 int ledOnMS = ledno.ledOnMS;
3610 int ledOffMS = ledno.ledOffMS;
3611 if ((ledno.defaults & Notification.DEFAULT_LIGHTS) != 0) {
Mike Lockwood670f9322010-01-20 12:13:36 -05003612 ledARGB = mDefaultNotificationColor;
3613 ledOnMS = mDefaultNotificationLedOn;
3614 ledOffMS = mDefaultNotificationLedOff;
3615 }
3616 if (mNotificationPulseEnabled) {
3617 // pulse repeatedly
Adam Lesinski182f73f2013-12-05 16:48:06 -08003618 mNotificationLight.setFlashing(ledARGB, Light.LIGHT_FLASH_TIMED,
Mike Lockwood670f9322010-01-20 12:13:36 -05003619 ledOnMS, ledOffMS);
Mike Lockwood670f9322010-01-20 12:13:36 -05003620 }
Wei Liu97e56662016-03-04 10:52:33 -08003621 if (mStatusBar != null) {
3622 // let SystemUI make an independent decision
3623 mStatusBar.notificationLightPulse(ledARGB, ledOnMS, ledOffMS);
3624 }
The Android Open Source Project10592532009-03-18 17:39:46 -07003625 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003626 }
3627
3628 // lock on mNotificationList
Adam Lesinski182f73f2013-12-05 16:48:06 -08003629 int indexOfNotificationLocked(String pkg, String tag, int id, int userId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003630 {
3631 ArrayList<NotificationRecord> list = mNotificationList;
3632 final int len = list.size();
3633 for (int i=0; i<len; i++) {
3634 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01003635 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
3636 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003637 return i;
3638 }
3639 }
3640 return -1;
3641 }
3642
Christoph Studer71f18fd2014-05-20 17:02:04 +02003643 // lock on mNotificationList
3644 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02003645 final int N = mNotificationList.size();
3646 for (int i = 0; i < N; i++) {
3647 if (key.equals(mNotificationList.get(i).getKey())) {
3648 return i;
3649 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02003650 }
Christoph Studerc5115552014-06-12 20:22:31 +02003651 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02003652 }
3653
Mike Lockwoodc22404a2009-12-02 11:15:02 -05003654 private void updateNotificationPulse() {
3655 synchronized (mNotificationList) {
3656 updateLightsLocked();
3657 }
3658 }
John Spurlocke677d712014-02-13 12:52:19 -05003659
John Spurlock7340fc82014-04-24 18:50:12 -04003660 private static boolean isUidSystem(int uid) {
3661 final int appid = UserHandle.getAppId(uid);
3662 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
3663 }
John Spurlockb408e8e2014-04-23 21:12:45 -04003664
John Spurlock7340fc82014-04-24 18:50:12 -04003665 private static boolean isCallerSystem() {
3666 return isUidSystem(Binder.getCallingUid());
3667 }
3668
3669 private static void checkCallerIsSystem() {
3670 if (isCallerSystem()) {
3671 return;
3672 }
3673 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
3674 }
3675
3676 private static void checkCallerIsSystemOrSameApp(String pkg) {
3677 if (isCallerSystem()) {
3678 return;
3679 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003680 checkCallerIsSameApp(pkg);
3681 }
3682
3683 private static void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04003684 final int uid = Binder.getCallingUid();
3685 try {
3686 ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
3687 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04003688 if (ai == null) {
3689 throw new SecurityException("Unknown package " + pkg);
3690 }
John Spurlock7340fc82014-04-24 18:50:12 -04003691 if (!UserHandle.isSameApp(ai.uid, uid)) {
3692 throw new SecurityException("Calling uid " + uid + " gave package"
3693 + pkg + " which is owned by uid " + ai.uid);
3694 }
3695 } catch (RemoteException re) {
3696 throw new SecurityException("Unknown package " + pkg + "\n" + re);
3697 }
3698 }
3699
John Spurlock32fe4c62014-10-02 12:16:02 -04003700 private static String callStateToString(int state) {
3701 switch (state) {
3702 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
3703 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
3704 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
3705 default: return "CALL_STATE_UNKNOWN_" + state;
3706 }
3707 }
3708
3709 private void listenForCallState() {
3710 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
3711 @Override
3712 public void onCallStateChanged(int state, String incomingNumber) {
3713 if (mCallState == state) return;
3714 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
3715 mCallState = state;
3716 }
3717 }, PhoneStateListener.LISTEN_CALL_STATE);
3718 }
3719
Christoph Studer05ad4822014-05-16 14:16:03 +02003720 /**
3721 * Generates a NotificationRankingUpdate from 'sbns', considering only
3722 * notifications visible to the given listener.
Chris Wren333a61c2014-05-28 16:40:57 -04003723 *
3724 * <p>Caller must hold a lock on mNotificationList.</p>
Christoph Studer05ad4822014-05-16 14:16:03 +02003725 */
Chris Wren333a61c2014-05-28 16:40:57 -04003726 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04003727 final int N = mNotificationList.size();
3728 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02003729 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05003730 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003731 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003732 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003733 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05003734 Bundle explanation = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04003735 for (int i = 0; i < N; i++) {
3736 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02003737 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02003738 continue;
3739 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003740 final String key = record.sbn.getKey();
3741 keys.add(key);
3742 importance.add(record.getImportance());
3743 if (record.getImportanceExplanation() != null) {
3744 explanation.putCharSequence(key, record.getImportanceExplanation());
3745 }
Chris Wren333a61c2014-05-28 16:40:57 -04003746 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05003747 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05003748
Christoph Studer05ad4822014-05-16 14:16:03 +02003749 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003750 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003751 if (record.getPackageVisibilityOverride()
3752 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05003753 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003754 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003755 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Christoph Studer05ad4822014-05-16 14:16:03 +02003756 }
Chris Wrenbdf33762015-12-04 15:50:51 -05003757 final int M = keys.size();
3758 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02003759 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05003760 int[] importanceAr = new int[M];
3761 for (int i = 0; i < M; i++) {
3762 importanceAr[i] = importance.get(i);
3763 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04003764 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003765 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys);
Christoph Studer05ad4822014-05-16 14:16:03 +02003766 }
3767
Christoph Studercef37cf2014-07-25 14:18:17 +02003768 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
3769 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
3770 return false;
3771 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07003772 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02003773 return true;
3774 }
3775
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00003776 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003777 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003778 try {
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00003779 return AppGlobals.getPackageManager().isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003780 } catch (RemoteException re) {
3781 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00003782 } catch (IllegalArgumentException ex) {
3783 // Package not found.
3784 return false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003785 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00003786 }
3787
Chris Wren47633422016-01-22 09:56:59 -05003788 private class TrimCache {
3789 StatusBarNotification heavy;
3790 StatusBarNotification sbnClone;
3791 StatusBarNotification sbnCloneLight;
3792
3793 TrimCache(StatusBarNotification sbn) {
3794 heavy = sbn;
3795 }
3796
3797 StatusBarNotification ForListener(ManagedServiceInfo info) {
3798 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
3799 if (sbnCloneLight == null) {
3800 sbnCloneLight = heavy.cloneLight();
3801 }
3802 return sbnCloneLight;
3803 } else {
3804 if (sbnClone == null) {
3805 sbnClone = heavy.clone();
3806 }
3807 return sbnClone;
3808 }
3809 }
3810 }
3811
Chris Wren0efdb882016-03-01 17:17:47 -05003812 public class NotificationRankers extends ManagedServices {
Chris Wren51017d02015-12-15 15:34:46 -05003813
Chris Wren0efdb882016-03-01 17:17:47 -05003814 public NotificationRankers() {
Chris Wren51017d02015-12-15 15:34:46 -05003815 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3816 }
3817
3818 @Override
3819 protected Config getConfig() {
3820 Config c = new Config();
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003821 c.caption = "notification ranker service";
3822 c.serviceInterface = NotificationRankerService.SERVICE_INTERFACE;
3823 c.secureSettingName = null;
3824 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_RANKER_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05003825 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003826 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05003827 return c;
3828 }
3829
3830 @Override
3831 protected IInterface asInterface(IBinder binder) {
3832 return INotificationListener.Stub.asInterface(binder);
3833 }
3834
3835 @Override
3836 protected boolean checkType(IInterface service) {
3837 return service instanceof INotificationListener;
3838 }
3839
3840 @Override
3841 protected void onServiceAdded(ManagedServiceInfo info) {
3842 mListeners.registerGuestService(info);
3843 }
3844
3845 @Override
3846 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
3847 mListeners.unregisterService(removed.service, removed.userid);
3848 }
Chris Wren47633422016-01-22 09:56:59 -05003849
3850 public void onNotificationEnqueued(final NotificationRecord r) {
3851 final StatusBarNotification sbn = r.sbn;
3852 TrimCache trimCache = new TrimCache(sbn);
3853
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003854 // mServices is the list inside ManagedServices of all the rankers,
Chris Wren47633422016-01-22 09:56:59 -05003855 // There should be only one, but it's a list, so while we enforce
3856 // singularity elsewhere, we keep it general here, to avoid surprises.
Chris Wren0efdb882016-03-01 17:17:47 -05003857 for (final ManagedServiceInfo info : NotificationRankers.this.mServices) {
Chris Wren47633422016-01-22 09:56:59 -05003858 boolean sbnVisible = isVisibleToListener(sbn, info);
3859 if (!sbnVisible) {
3860 continue;
3861 }
3862
3863 final int importance = r.getImportance();
3864 final boolean fromUser = r.isImportanceFromUser();
3865 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003866 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05003867 @Override
3868 public void run() {
3869 notifyEnqueued(info, sbnToPost, importance, fromUser);
3870 }
3871 });
3872 }
3873 }
3874
3875 private void notifyEnqueued(final ManagedServiceInfo info,
3876 final StatusBarNotification sbn, int importance, boolean fromUser) {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003877 final INotificationListener ranker = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05003878 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
3879 try {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003880 ranker.onNotificationEnqueued(sbnHolder, importance, fromUser);
Chris Wren47633422016-01-22 09:56:59 -05003881 } catch (RemoteException ex) {
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003882 Log.e(TAG, "unable to notify ranker (enqueued): " + ranker, ex);
Chris Wren47633422016-01-22 09:56:59 -05003883 }
3884 }
3885
3886 public boolean isEnabled() {
3887 return !mServices.isEmpty();
3888 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003889
3890 @Override
3891 public void onUserSwitched(int user) {
Julia Reynoldsad929572016-05-26 13:49:17 -04003892 synchronized (mNotificationList) {
Julia Reynolds00d9d9f2016-06-21 07:47:22 -04003893 int i = mServices.size()-1;
3894 while (i --> 0) {
3895 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldsad929572016-05-26 13:49:17 -04003896 unregisterService(info.service, info.userid);
3897 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003898 }
3899 registerRanker();
3900 }
3901
3902 @Override
3903 public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
3904 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
3905 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList)));
Chris Wren88d2f6d2016-03-17 15:47:09 -04003906 if (mRankerServicePackageName == null) {
3907 return;
3908 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003909
3910 if (pkgList != null && (pkgList.length > 0)) {
3911 for (String pkgName : pkgList) {
3912 if (mRankerServicePackageName.equals(pkgName)) {
3913 registerRanker();
3914 }
3915 }
3916 }
3917 }
3918
3919 protected void registerRanker() {
3920 // Find the updatable ranker and register it.
Chris Wren88d2f6d2016-03-17 15:47:09 -04003921 if (mRankerServicePackageName == null) {
3922 Slog.w(TAG, "could not start ranker service: no package specified!");
3923 return;
3924 }
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003925 Set<ComponentName> rankerComponents = queryPackageForServices(
Julia Reynoldsa3dc1fb2016-04-12 10:25:12 -04003926 mRankerServicePackageName, UserHandle.USER_SYSTEM);
Julia Reynolds1c9bd422016-03-15 09:25:56 -04003927 Iterator<ComponentName> iterator = rankerComponents.iterator();
3928 if (iterator.hasNext()) {
3929 ComponentName rankerComponent = iterator.next();
3930 if (iterator.hasNext()) {
3931 Slog.e(TAG, "found multiple ranker services:" + rankerComponents);
3932 } else {
3933 registerSystemService(rankerComponent, UserHandle.USER_SYSTEM);
3934 }
3935 } else {
3936 Slog.w(TAG, "could not start ranker service: none found");
3937 }
3938 }
Chris Wren51017d02015-12-15 15:34:46 -05003939 }
3940
John Spurlock7340fc82014-04-24 18:50:12 -04003941 public class NotificationListeners extends ManagedServices {
3942
Christoph Studerb82bc782014-08-20 14:29:43 +02003943 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
3944
John Spurlock7340fc82014-04-24 18:50:12 -04003945 public NotificationListeners() {
3946 super(getContext(), mHandler, mNotificationList, mUserProfiles);
3947 }
3948
3949 @Override
3950 protected Config getConfig() {
3951 Config c = new Config();
3952 c.caption = "notification listener";
3953 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
3954 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
3955 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
3956 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
3957 c.clientLabel = R.string.notification_listener_binding_label;
3958 return c;
3959 }
3960
3961 @Override
3962 protected IInterface asInterface(IBinder binder) {
3963 return INotificationListener.Stub.asInterface(binder);
3964 }
3965
3966 @Override
Chris Wren51017d02015-12-15 15:34:46 -05003967 protected boolean checkType(IInterface service) {
3968 return service instanceof INotificationListener;
3969 }
3970
3971 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04003972 public void onServiceAdded(ManagedServiceInfo info) {
3973 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04003974 final NotificationRankingUpdate update;
Christoph Studer05ad4822014-05-16 14:16:03 +02003975 synchronized (mNotificationList) {
Chris Wren333a61c2014-05-28 16:40:57 -04003976 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02003977 }
John Spurlock7340fc82014-04-24 18:50:12 -04003978 try {
Chris Wren333a61c2014-05-28 16:40:57 -04003979 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04003980 } catch (RemoteException e) {
3981 // we tried
3982 }
3983 }
3984
John Spurlock1fa865f2014-07-21 14:56:39 -04003985 @Override
3986 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003987 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003988 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01003989 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04003990 }
Christoph Studerb82bc782014-08-20 14:29:43 +02003991 mLightTrimListeners.remove(removed);
3992 }
3993
3994 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
3995 if (trim == TRIM_LIGHT) {
3996 mLightTrimListeners.add(info);
3997 } else {
3998 mLightTrimListeners.remove(info);
3999 }
4000 }
4001
4002 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
4003 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04004004 }
4005
John Spurlock7340fc82014-04-24 18:50:12 -04004006 /**
4007 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02004008 *
4009 * <p>
4010 * Also takes care of removing a notification that has been visible to a listener before,
4011 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04004012 */
Christoph Studercef37cf2014-07-25 14:18:17 +02004013 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
Christoph Studerb82bc782014-08-20 14:29:43 +02004014 // Lazily initialized snapshots of the notification.
Chris Wren47633422016-01-22 09:56:59 -05004015 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02004016
John Spurlock7340fc82014-04-24 18:50:12 -04004017 for (final ManagedServiceInfo info : mServices) {
Christoph Studercef37cf2014-07-25 14:18:17 +02004018 boolean sbnVisible = isVisibleToListener(sbn, info);
4019 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
4020 // This notification hasn't been and still isn't visible -> ignore.
4021 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02004022 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04004023 }
Chris Wren333a61c2014-05-28 16:40:57 -04004024 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02004025
4026 // This notification became invisible -> remove the old one.
4027 if (oldSbnVisible && !sbnVisible) {
4028 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
4029 mHandler.post(new Runnable() {
4030 @Override
4031 public void run() {
4032 notifyRemoved(info, oldSbnLightClone, update);
4033 }
4034 });
Christoph Studer05ad4822014-05-16 14:16:03 +02004035 continue;
4036 }
Christoph Studercef37cf2014-07-25 14:18:17 +02004037
Chris Wren47633422016-01-22 09:56:59 -05004038 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02004039 mHandler.post(new Runnable() {
4040 @Override
4041 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02004042 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02004043 }
4044 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004045 }
4046 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004047
John Spurlock7340fc82014-04-24 18:50:12 -04004048 /**
4049 * asynchronously notify all listeners about a removed notification
4050 */
Chris Wren333a61c2014-05-28 16:40:57 -04004051 public void notifyRemovedLocked(StatusBarNotification sbn) {
John Spurlock7340fc82014-04-24 18:50:12 -04004052 // make a copy in case changes are made to the underlying Notification object
4053 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
4054 // notification
4055 final StatusBarNotification sbnLight = sbn.cloneLight();
Chris Wrenf9536642014-04-17 10:01:54 -04004056 for (final ManagedServiceInfo info : mServices) {
Christoph Studercef37cf2014-07-25 14:18:17 +02004057 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02004058 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04004059 }
Chris Wren333a61c2014-05-28 16:40:57 -04004060 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02004061 mHandler.post(new Runnable() {
4062 @Override
4063 public void run() {
Christoph Studercef37cf2014-07-25 14:18:17 +02004064 notifyRemoved(info, sbnLight, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02004065 }
4066 });
Chris Wrenf9536642014-04-17 10:01:54 -04004067 }
4068 }
4069
4070 /**
4071 * asynchronously notify all listeners about a reordering of notifications
Chris Wrenf9536642014-04-17 10:01:54 -04004072 */
Chris Wren333a61c2014-05-28 16:40:57 -04004073 public void notifyRankingUpdateLocked() {
Chris Wrenf9536642014-04-17 10:01:54 -04004074 for (final ManagedServiceInfo serviceInfo : mServices) {
Christoph Studer05ad4822014-05-16 14:16:03 +02004075 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4076 continue;
4077 }
Christoph Studercef37cf2014-07-25 14:18:17 +02004078 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
John Spurlock7340fc82014-04-24 18:50:12 -04004079 mHandler.post(new Runnable() {
4080 @Override
4081 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -04004082 notifyRankingUpdate(serviceInfo, update);
John Spurlock7340fc82014-04-24 18:50:12 -04004083 }
4084 });
Kenny Guya263e4e2014-03-03 18:24:03 +00004085 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004086 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004087
John Spurlockd8afe3c2014-08-01 14:04:07 -04004088 public void notifyListenerHintsChangedLocked(final int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04004089 for (final ManagedServiceInfo serviceInfo : mServices) {
4090 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4091 continue;
4092 }
4093 mHandler.post(new Runnable() {
4094 @Override
4095 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004096 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004097 }
4098 });
4099 }
4100 }
4101
Christoph Studer85a384b2014-08-27 20:16:15 +02004102 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
4103 for (final ManagedServiceInfo serviceInfo : mServices) {
4104 if (!serviceInfo.isEnabledForCurrentProfiles()) {
4105 continue;
4106 }
4107 mHandler.post(new Runnable() {
4108 @Override
4109 public void run() {
4110 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
4111 }
4112 });
4113 }
4114 }
4115
Christoph Studercef37cf2014-07-25 14:18:17 +02004116 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02004117 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
John Spurlock7340fc82014-04-24 18:50:12 -04004118 final INotificationListener listener = (INotificationListener)info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004119 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04004120 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07004121 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04004122 } catch (RemoteException ex) {
4123 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
4124 }
4125 }
4126
Christoph Studercef37cf2014-07-25 14:18:17 +02004127 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Christoph Studer05ad4822014-05-16 14:16:03 +02004128 NotificationRankingUpdate rankingUpdate) {
John Spurlock7340fc82014-04-24 18:50:12 -04004129 if (!info.enabledAndUserMatches(sbn.getUserId())) {
4130 return;
4131 }
Christoph Studer05ad4822014-05-16 14:16:03 +02004132 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004133 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04004134 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07004135 listener.onNotificationRemoved(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04004136 } catch (RemoteException ex) {
4137 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04004138 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004139 }
Chris Wrenf9536642014-04-17 10:01:54 -04004140
Christoph Studer05ad4822014-05-16 14:16:03 +02004141 private void notifyRankingUpdate(ManagedServiceInfo info,
4142 NotificationRankingUpdate rankingUpdate) {
4143 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04004144 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02004145 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04004146 } catch (RemoteException ex) {
4147 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
4148 }
4149 }
John Spurlock1fa865f2014-07-21 14:56:39 -04004150
John Spurlockd8afe3c2014-08-01 14:04:07 -04004151 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04004152 final INotificationListener listener = (INotificationListener) info.service;
4153 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004154 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004155 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004156 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04004157 }
4158 }
Justin Koh38156c52014-06-04 13:57:49 -07004159
Christoph Studer85a384b2014-08-27 20:16:15 +02004160 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
4161 int interruptionFilter) {
4162 final INotificationListener listener = (INotificationListener) info.service;
4163 try {
4164 listener.onInterruptionFilterChanged(interruptionFilter);
4165 } catch (RemoteException ex) {
4166 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
4167 }
4168 }
4169
Justin Koh38156c52014-06-04 13:57:49 -07004170 private boolean isListenerPackage(String packageName) {
4171 if (packageName == null) {
4172 return false;
4173 }
4174 // TODO: clean up locking object later
4175 synchronized (mNotificationList) {
4176 for (final ManagedServiceInfo serviceInfo : mServices) {
4177 if (packageName.equals(serviceInfo.component.getPackageName())) {
4178 return true;
4179 }
4180 }
4181 }
4182 return false;
4183 }
Kenny Guya263e4e2014-03-03 18:24:03 +00004184 }
John Spurlock25e2d242014-06-27 13:58:23 -04004185
4186 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04004187 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04004188 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04004189 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04004190 public long since;
4191 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04004192 public boolean redact = true;
John Spurlock25e2d242014-06-27 13:58:23 -04004193
4194 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04004195 final DumpFilter filter = new DumpFilter();
4196 for (int ai = 0; ai < args.length; ai++) {
4197 final String a = args[ai];
4198 if ("--noredact".equals(a) || "--reveal".equals(a)) {
4199 filter.redact = false;
4200 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
4201 if (ai < args.length-1) {
4202 ai++;
4203 filter.pkgFilter = args[ai].trim().toLowerCase();
4204 if (filter.pkgFilter.isEmpty()) {
4205 filter.pkgFilter = null;
4206 } else {
4207 filter.filtered = true;
4208 }
4209 }
4210 } else if ("--zen".equals(a) || "zen".equals(a)) {
4211 filter.filtered = true;
4212 filter.zen = true;
4213 } else if ("--stats".equals(a)) {
4214 filter.stats = true;
4215 if (ai < args.length-1) {
4216 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01004217 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04004218 } else {
4219 filter.since = 0;
4220 }
4221 }
John Spurlock25e2d242014-06-27 13:58:23 -04004222 }
Dan Sandlera1770312015-07-10 13:59:29 -04004223 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04004224 }
4225
4226 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04004227 if (!filtered) return true;
4228 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04004229 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04004230 }
4231
4232 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04004233 if (!filtered) return true;
4234 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04004235 }
4236
4237 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04004238 if (!filtered) return true;
4239 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04004240 }
4241
4242 @Override
4243 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04004244 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04004245 }
4246 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07004247
4248 /**
4249 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
4250 * binder without sending large amounts of data over a oneway transaction.
4251 */
4252 private static final class StatusBarNotificationHolder
4253 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07004254 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004255
4256 public StatusBarNotificationHolder(StatusBarNotification value) {
4257 mValue = value;
4258 }
4259
Griff Hazene9aac5f2014-09-05 20:04:09 -07004260 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07004261 @Override
4262 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07004263 StatusBarNotification value = mValue;
4264 mValue = null;
4265 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07004266 }
4267 }
John Spurlock7c74f782015-06-04 13:01:42 -04004268
4269 private final class PolicyAccess {
4270 private static final String SEPARATOR = ":";
4271 private final String[] PERM = {
4272 android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
4273 };
4274
4275 public boolean isPackageGranted(String pkg) {
4276 return pkg != null && getGrantedPackages().contains(pkg);
4277 }
4278
4279 public void put(String pkg, boolean granted) {
4280 if (pkg == null) return;
4281 final ArraySet<String> pkgs = getGrantedPackages();
4282 boolean changed;
4283 if (granted) {
4284 changed = pkgs.add(pkg);
4285 } else {
4286 changed = pkgs.remove(pkg);
4287 }
4288 if (!changed) return;
4289 final String setting = TextUtils.join(SEPARATOR, pkgs);
4290 final int currentUser = ActivityManager.getCurrentUser();
4291 Settings.Secure.putStringForUser(getContext().getContentResolver(),
4292 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4293 setting,
4294 currentUser);
4295 getContext().sendBroadcastAsUser(new Intent(NotificationManager
4296 .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4297 .setPackage(pkg)
4298 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
4299 }
4300
4301 public ArraySet<String> getGrantedPackages() {
4302 final ArraySet<String> pkgs = new ArraySet<>();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04004303
4304 long identity = Binder.clearCallingIdentity();
4305 try {
4306 final String setting = Settings.Secure.getStringForUser(
4307 getContext().getContentResolver(),
4308 Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
4309 ActivityManager.getCurrentUser());
4310 if (setting != null) {
4311 final String[] tokens = setting.split(SEPARATOR);
4312 for (int i = 0; i < tokens.length; i++) {
4313 String token = tokens[i];
4314 if (token != null) {
Andreas Gampe1ed71f32015-12-11 15:49:07 -08004315 token = token.trim();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04004316 }
4317 if (TextUtils.isEmpty(token)) {
4318 continue;
4319 }
4320 pkgs.add(token);
John Spurlock7c74f782015-06-04 13:01:42 -04004321 }
John Spurlock7c74f782015-06-04 13:01:42 -04004322 }
Julia Reynoldsea6c4482015-08-13 09:01:33 -04004323 } finally {
4324 Binder.restoreCallingIdentity(identity);
John Spurlock7c74f782015-06-04 13:01:42 -04004325 }
4326 return pkgs;
4327 }
4328
4329 public String[] getRequestingPackages() throws RemoteException {
4330 final ParceledListSlice list = AppGlobals.getPackageManager()
4331 .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
4332 ActivityManager.getCurrentUser());
4333 final List<PackageInfo> pkgs = list.getList();
4334 if (pkgs == null || pkgs.isEmpty()) return new String[0];
4335 final int N = pkgs.size();
4336 final String[] rt = new String[N];
4337 for (int i = 0; i < N; i++) {
4338 rt[i] = pkgs.get(i).packageName;
4339 }
4340 return rt;
4341 }
4342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004343}