blob: 16b92573f22222cb6be78fd9d2f8888abe2b17d2 [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
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050019import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
20import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040021import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040022import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040023import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050024import static android.content.pm.PackageManager.FEATURE_LEANBACK;
25import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynolds4db59552017-06-30 13:34:01 -040026import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Julia Reynolds88a879f2017-07-26 17:06:46 -040027import static android.os.UserHandle.USER_NULL;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040028import static android.service.notification.NotificationListenerService
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050029 .HINT_HOST_DISABLE_CALL_EFFECTS;
30import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
31import static android.service.notification.NotificationListenerService
32 .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
33import static android.service.notification.NotificationListenerService
Julia Reynolds73ed76b2017-04-04 17:04:38 -040034 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
35import static android.service.notification.NotificationListenerService
36 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
37import static android.service.notification.NotificationListenerService
38 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050039import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
40import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040041import static android.service.notification.NotificationListenerService.REASON_CANCEL;
42import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050043import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040044import static android.service.notification.NotificationListenerService.REASON_CLICK;
45import static android.service.notification.NotificationListenerService.REASON_ERROR;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050046import static android.service.notification.NotificationListenerService
47 .REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050048import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
49import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
50import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
51import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
52import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
53import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
54import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050055import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050056import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
57import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Julia Reynoldsd5607292016-02-05 15:25:58 -050058import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
Julia Reynolds61721582016-01-05 08:35:25 -050059import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
Christoph Studerb82bc782014-08-20 14:29:43 +020060import static android.service.notification.NotificationListenerService.TRIM_FULL;
61import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070062import static android.view.Display.DEFAULT_DISPLAY;
63import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070064
Chris Wren51017d02015-12-15 15:34:46 -050065import android.Manifest;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040066import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080067import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070068import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070069import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050070import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040071import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050072import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040073import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import android.app.IActivityManager;
75import android.app.INotificationManager;
76import android.app.ITransientNotification;
77import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040078import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050079import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -050080import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050081import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.app.PendingIntent;
83import android.app.StatusBarManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050084import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070085import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070086import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040087import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070089import android.content.ComponentName;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070090import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.content.Context;
92import android.content.Intent;
93import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040094import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +000095import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096import android.content.pm.PackageManager;
97import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +020098import android.content.pm.ParceledListSlice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700100import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400101import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700102import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500103import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700104import android.media.IRingtonePlayer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400107import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400108import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400109import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400111import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112import android.os.IBinder;
John Spurlock7340fc82014-04-24 18:50:12 -0400113import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400114import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700116import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700117import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400118import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400119import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400120import android.os.ShellCallback;
121import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400122import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100123import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700124import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000125import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500126import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800127import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400128import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400129import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400130import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400131import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700132import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700133import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500134import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400135import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200136import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500137import android.service.notification.NotificationRecordProto;
138import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400139import android.service.notification.NotificationStats;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500140import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700141import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400142import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500143import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400144import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500145import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700146import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400147import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400148import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700149import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800151import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700152import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400153import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500154import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700155import android.view.accessibility.AccessibilityEvent;
156import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000158
Scott Greenwald9a05b312013-06-28 00:37:54 -0400159import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400160import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400161import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500162import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500163import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500164import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700165import com.android.internal.os.BackgroundThread;
Chris Wrend1dbc922015-06-19 17:51:16 -0400166import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400167import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600168import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400169import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400170import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400171import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700172import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800173import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700174import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800175import com.android.server.SystemService;
176import com.android.server.lights.Light;
177import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400178import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500179import com.android.server.notification.ManagedServices.UserProfiles;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700180import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400181import com.android.server.statusbar.StatusBarManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100182import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800183
John Spurlockb408e8e2014-04-23 21:12:45 -0400184import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000185
Chris Wrene4b38802015-07-07 15:54:19 -0400186import org.json.JSONException;
187import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700188import org.xmlpull.v1.XmlPullParser;
189import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400190import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700191
John Spurlock35ef0a62015-05-28 11:24:10 -0400192import java.io.ByteArrayInputStream;
193import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400194import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400196import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400197import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400198import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400199import java.io.InputStream;
200import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100202import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500203import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000205import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500206import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400207import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200208import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500209import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400210import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500211import java.util.concurrent.TimeUnit;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400212
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400213/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800214public class NotificationManagerService extends SystemService {
215 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100216 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800217 public static final boolean ENABLE_CHILD_NOTIFICATIONS
218 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219
Adam Lesinski182f73f2013-12-05 16:48:06 -0800220 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400221 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 // message codes
Adam Lesinski182f73f2013-12-05 16:48:06 -0800224 static final int MESSAGE_TIMEOUT = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400225 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500226 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
227 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
228 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
229
230 // ranking thread messages
231 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
232 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700234 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800235 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800236
Adam Lesinski182f73f2013-12-05 16:48:06 -0800237 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200238
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500239 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
240
Adam Lesinski182f73f2013-12-05 16:48:06 -0800241 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
Adam Lesinski182f73f2013-12-05 16:48:06 -0800243 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500244
Adam Lesinski182f73f2013-12-05 16:48:06 -0800245 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400246
Christoph Studer12aeda82014-09-23 19:08:56 +0200247 // When #matchesCallFilter is called from the ringer, wait at most
248 // 3s to resolve the contacts. This timeout is required since
249 // ContactsProvider might take a long time to start up.
250 //
251 // Return STARRED_CONTACT when the timeout is hit in order to avoid
252 // missed calls in ZEN mode "Important".
253 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
254 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
255 ValidateNotificationPeople.STARRED_CONTACT;
256
Christoph Studer265c1052014-07-23 17:14:33 +0200257 /** notification_enqueue status value for a newly enqueued notification. */
258 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
259
260 /** notification_enqueue status value for an existing notification. */
261 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
262
263 /** notification_enqueue status value for an ignored notification. */
264 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400265 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200266
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500267 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
268
Julia Reynolds2a128742016-11-28 14:29:25 -0500269 private static final String ACTION_NOTIFICATION_TIMEOUT =
270 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
271 private static final int REQUEST_CODE_TIMEOUT = 1;
272 private static final String SCHEME_TIMEOUT = "timeout";
273 private static final String EXTRA_KEY = "key";
274
Adam Lesinski182f73f2013-12-05 16:48:06 -0800275 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400276 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500277 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500278 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800279 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500280 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800281 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800282 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700283 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500284 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400285 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400286 private AccessibilityManager mAccessibilityManager;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400289 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400290 private final HandlerThread mRankingThread = new HandlerThread("ranker",
291 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292
Adam Lesinski182f73f2013-12-05 16:48:06 -0800293 private Light mNotificationLight;
294 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800295
Daniel Sandleredbb3802012-11-13 20:49:47 -0800296 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400297 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800298 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800299
John Spurlockd8afe3c2014-08-01 14:04:07 -0400300 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400301 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500302 private String mSoundNotificationKey;
303 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304
Bryce Lee7219ada2016-04-08 10:54:23 -0700305 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400306 new SparseArray<>();
307 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400308 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500309 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400310
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500311 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400312 private boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400313 protected boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500314 private boolean mNotificationPulseEnabled;
315
Beverly5d463b62017-07-26 14:13:40 -0400316 private Uri mInCallNotificationUri;
317 private AudioAttributes mInCallNotificationAudioAttributes;
318 private float mInCallNotificationVolume;
Marta Białka39c992f2011-03-10 10:27:24 +0100319
Daniel Sandler09a247e2013-02-14 10:24:17 -0500320 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500321 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400322 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400323 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400324 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400325 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400326 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500327 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400328 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400329 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400330 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200331 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332
Chris Wren6054e612014-11-25 17:16:46 -0500333 // The last key in this list owns the hardware.
334 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700335
Adam Lesinski182f73f2013-12-05 16:48:06 -0800336 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700337 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500338
Griff Hazen9f637d12014-06-10 11:13:51 -0700339 private Archive mArchive;
340
John Spurlock21258a32015-05-27 18:22:55 -0400341 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400342 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400343
Daniel Sandler0da673f2012-04-11 12:33:16 -0400344 private static final int DB_VERSION = 1;
345
John Spurlock21258a32015-05-27 18:22:55 -0400346 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400347 private static final String ATTR_VERSION = "version";
348
Chris Wren54bbef42014-07-09 18:37:56 -0400349 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400350
John Spurlockb408e8e2014-04-23 21:12:45 -0400351 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400352 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400353 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400354 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200355 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100356
John Spurlocke6a7d932014-03-13 12:29:00 -0400357 private static final int MY_UID = Process.myUid();
358 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700359 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500360 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400361 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400362 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400363
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400364 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400365 private GroupHelper mGroupHelper;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500366 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400367
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500368 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700369 final int mBufferSize;
370 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500371
Griff Hazen9f637d12014-06-10 11:13:51 -0700372 public Archive(int size) {
373 mBufferSize = size;
374 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500375 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700376
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400377 public String toString() {
378 final StringBuilder sb = new StringBuilder();
379 final int N = mBuffer.size();
380 sb.append("Archive (");
381 sb.append(N);
382 sb.append(" notification");
383 sb.append((N==1)?")":"s)");
384 return sb.toString();
385 }
386
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500387 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700388 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500389 mBuffer.removeFirst();
390 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400391
392 // We don't want to store the heavy bits of the notification in the archive,
393 // but other clients in the system process might be using the object, so we
394 // store a (lightened) copy.
395 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500396 }
397
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500398 public Iterator<StatusBarNotification> descendingIterator() {
399 return mBuffer.descendingIterator();
400 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500401
402 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700403 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500404 final StatusBarNotification[] a
405 = new StatusBarNotification[Math.min(count, mBuffer.size())];
406 Iterator<StatusBarNotification> iter = descendingIterator();
407 int i=0;
408 while (iter.hasNext() && i < count) {
409 a[i++] = iter.next();
410 }
411 return a;
412 }
413
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500414 }
415
Julia Reynolds88a879f2017-07-26 17:06:46 -0400416 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400417 String defaultListenerAccess = getContext().getResources().getString(
418 com.android.internal.R.string.config_defaultListenerAccessPackages);
419 if (defaultListenerAccess != null) {
420 for (String whitelisted :
421 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
422 // Gather all notification listener components for candidate pkgs.
423 Set<ComponentName> approvedListeners =
424 mListeners.queryPackageForServices(whitelisted,
425 PackageManager.MATCH_DIRECT_BOOT_AWARE
426 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
427 for (ComponentName cn : approvedListeners) {
428 try {
429 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
430 userId, true);
431 } catch (RemoteException e) {
432 e.printStackTrace();
433 }
434 }
435 }
436 }
437 String defaultDndAccess = getContext().getResources().getString(
438 com.android.internal.R.string.config_defaultDndAccessPackages);
439 if (defaultListenerAccess != null) {
440 for (String whitelisted :
441 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
442 try {
443 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
444 } catch (RemoteException e) {
445 e.printStackTrace();
446 }
447 }
448 }
449 }
450
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400451 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400452 throws XmlPullParserException, NumberFormatException, IOException {
453 final XmlPullParser parser = Xml.newPullParser();
454 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400455 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
456 boolean migratedManagedServices = false;
457 int outerDepth = parser.getDepth();
458 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
459 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
460 mZenModeHelper.readXml(parser, forRestore);
461 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
462 mRankingHelper.readXml(parser, forRestore);
463 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400464 // No non-system managed services are allowed on low ram devices
Julia Reynoldse1816412017-10-24 10:39:11 -0400465 if (canUseManagedServices()) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400466 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
467 mListeners.readXml(parser);
468 migratedManagedServices = true;
469 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
470 mAssistants.readXml(parser);
471 migratedManagedServices = true;
472 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
473 mConditionProviders.readXml(parser);
474 migratedManagedServices = true;
475 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400476 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400477 }
478
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400479 if (!migratedManagedServices) {
480 mListeners.migrateToXml();
481 mAssistants.migrateToXml();
482 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400483 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400484 }
485 }
486
John Spurlock056c5192014-04-20 21:52:01 -0400487 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400488 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500489 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400490
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400491 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400492 try {
493 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400494 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400495 } catch (FileNotFoundException e) {
496 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400497 // Load default managed services approvals
Julia Reynolds88a879f2017-07-26 17:06:46 -0400498 readDefaultApprovedServices(UserHandle.USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400499 } catch (IOException e) {
500 Log.wtf(TAG, "Unable to read notification policy", e);
501 } catch (NumberFormatException e) {
502 Log.wtf(TAG, "Unable to parse notification policy", e);
503 } catch (XmlPullParserException e) {
504 Log.wtf(TAG, "Unable to parse notification policy", e);
505 } finally {
506 IoUtils.closeQuietly(infile);
507 }
508 }
509 }
510
511 public void savePolicyFile() {
512 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
513 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
514 }
515
516 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400517 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400518 synchronized (mPolicyFile) {
519 final FileOutputStream stream;
520 try {
521 stream = mPolicyFile.startWrite();
522 } catch (IOException e) {
523 Slog.w(TAG, "Failed to save policy file", e);
524 return;
525 }
526
527 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400528 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400529 mPolicyFile.finishWrite(stream);
530 } catch (IOException e) {
531 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
532 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400533 }
534 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400535 BackupManager.dataChanged(getContext().getPackageName());
536 }
537
538 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
539 final XmlSerializer out = new FastXmlSerializer();
540 out.setOutput(stream, StandardCharsets.UTF_8.name());
541 out.startDocument(null, true);
542 out.startTag(null, TAG_NOTIFICATION_POLICY);
543 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
544 mZenModeHelper.writeXml(out, forBackup);
545 mRankingHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400546 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400547 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400548 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400549 out.endTag(null, TAG_NOTIFICATION_POLICY);
550 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400551 }
552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 private static final class ToastRecord
554 {
555 final int pid;
556 final String pkg;
Beverly4ee785b2017-08-11 12:49:56 -0400557 ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700559 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700561 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
562 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 this.pid = pid;
564 this.pkg = pkg;
565 this.callback = callback;
566 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700567 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 }
569
570 void update(int duration) {
571 this.duration = duration;
572 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800573
Beverly4ee785b2017-08-11 12:49:56 -0400574 void update(ITransientNotification callback) {
575 this.callback = callback;
576 }
577
John Spurlock25e2d242014-06-27 13:58:23 -0400578 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
579 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 pw.println(prefix + this);
581 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 @Override
584 public final String toString()
585 {
586 return "ToastRecord{"
587 + Integer.toHexString(System.identityHashCode(this))
588 + " pkg=" + pkg
589 + " callback=" + callback
590 + " duration=" + duration;
591 }
592 }
593
Beverly40239d92017-07-07 10:20:41 -0400594 @VisibleForTesting
595 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596
Adam Lesinski182f73f2013-12-05 16:48:06 -0800597 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500599 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400600 mDisableNotificationEffects =
601 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400602 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 // cancel whatever's going on
604 long identity = Binder.clearCallingIdentity();
605 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800606 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700607 if (player != null) {
608 player.stopAsync();
609 }
610 } catch (RemoteException e) {
611 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 Binder.restoreCallingIdentity(identity);
613 }
614
615 identity = Binder.clearCallingIdentity();
616 try {
617 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700618 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 Binder.restoreCallingIdentity(identity);
620 }
621 }
622 }
623 }
624
Adam Lesinski182f73f2013-12-05 16:48:06 -0800625 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400626 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500627 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400628 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000629 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 }
632
Adam Lesinski182f73f2013-12-05 16:48:06 -0800633 @Override
Christoph Studer03b87a22014-04-30 17:33:27 +0200634 public void onNotificationClick(int callingUid, int callingPid, String key) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500635 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200636 NotificationRecord r = mNotificationsByKey.get(key);
637 if (r == null) {
638 Log.w(TAG, "No notification with key: " + key);
639 return;
640 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400641 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500642 MetricsLogger.action(r.getLogMaker(now)
643 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
644 .setType(MetricsEvent.TYPE_ACTION));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400645 EventLogTags.writeNotificationClicked(key,
646 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
647
Christoph Studer03b87a22014-04-30 17:33:27 +0200648 StatusBarNotification sbn = r.sbn;
649 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
650 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
651 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400652 REASON_CLICK, null);
Christoph Studer03b87a22014-04-30 17:33:27 +0200653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 }
655
Adam Lesinski182f73f2013-12-05 16:48:06 -0800656 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200657 public void onNotificationActionClick(int callingUid, int callingPid, String key,
658 int actionIndex) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500659 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200660 NotificationRecord r = mNotificationsByKey.get(key);
661 if (r == null) {
662 Log.w(TAG, "No notification with key: " + key);
663 return;
664 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400665 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500666 MetricsLogger.action(r.getLogMaker(now)
667 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
668 .setType(MetricsEvent.TYPE_ACTION)
669 .setSubtype(actionIndex));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400670 EventLogTags.writeNotificationActionClicked(key, actionIndex,
671 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Christoph Studer4da84cd2014-10-21 17:24:20 +0200672 // TODO: Log action click via UsageStats.
673 }
674 }
675
676 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400677 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400678 String pkg, String tag, int id, int userId, String key,
679 @NotificationStats.DismissalSurface int dismissalSurface) {
680 synchronized (mNotificationLock) {
681 NotificationRecord r = mNotificationsByKey.get(key);
682 if (r != null) {
683 r.recordDismissalSurface(dismissalSurface);
684 }
685 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400686 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000687 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400688 true, userId, REASON_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400689 }
690
Adam Lesinski182f73f2013-12-05 16:48:06 -0800691 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400692 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500693 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400694 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400695 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100696 if (clearEffects) {
697 clearEffects();
698 }
699 }
700
701 @Override
702 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500703 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100704 EventLogTags.writeNotificationPanelHidden();
705 }
706
707 @Override
708 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500709 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100710 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400711 clearSoundLocked();
712 clearVibrateLocked();
713 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 }
715 }
Joe Onorato005847b2010-06-04 16:08:02 -0400716
Adam Lesinski182f73f2013-12-05 16:48:06 -0800717 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400718 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000719 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400720 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
721 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400722 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400723 REASON_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700724 long ident = Binder.clearCallingIdentity();
725 try {
Christopher Tate8aa8fe12017-01-20 17:50:32 -0800726 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700727 "Bad notification posted from package " + pkg
728 + ": " + message);
729 } catch (RemoteException e) {
730 }
731 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400732 }
John Spurlocke677d712014-02-13 12:52:19 -0500733
734 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400735 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
736 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500737 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400738 for (NotificationVisibility nv : newlyVisibleKeys) {
739 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200740 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800741 if (!r.isSeen()) {
742 // Report to usage stats that notification was made visible
743 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
744 reportSeen(r);
745 }
Chris Wrend1dbc922015-06-19 17:51:16 -0400746 r.setVisibility(true, nv.rank);
747 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200748 }
749 // Note that we might receive this event after notifications
750 // have already left the system, e.g. after dismissing from the
751 // shade. Hence not finding notifications in
752 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400753 for (NotificationVisibility nv : noLongerVisibleKeys) {
754 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200755 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400756 r.setVisibility(false, nv.rank);
757 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200758 }
759 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200760 }
Chris Wren78403d72014-07-28 10:23:24 +0100761
762 @Override
763 public void onNotificationExpansionChanged(String key,
764 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500765 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100766 NotificationRecord r = mNotificationsByKey.get(key);
767 if (r != null) {
768 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400769 final long now = System.currentTimeMillis();
Chris Wrenf7342712017-09-14 10:55:55 -0400770 if (userAction) {
Chris Wren377ac6d2017-09-12 14:15:23 -0400771 MetricsLogger.action(r.getLogMaker(now)
772 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Chris Wrenf7342712017-09-14 10:55:55 -0400773 .setType(expanded ? MetricsEvent.TYPE_DETAIL
774 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400775 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500776 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400777 r.recordExpanded();
778 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400779 EventLogTags.writeNotificationExpansion(key,
780 userAction ? 1 : 0, expanded ? 1 : 0,
781 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100782 }
783 }
784 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400785
786 @Override
787 public void onNotificationDirectReplied(String key) {
788 synchronized (mNotificationLock) {
789 NotificationRecord r = mNotificationsByKey.get(key);
790 if (r != null) {
791 r.recordDirectReplied();
792 }
793 }
794 }
795
796 @Override
797 public void onNotificationSettingsViewed(String key) {
798 synchronized (mNotificationLock) {
799 NotificationRecord r = mNotificationsByKey.get(key);
800 if (r != null) {
801 r.recordViewedSettings();
802 }
803 }
804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 };
806
Julia Reynolds88860ce2017-06-01 16:55:49 -0400807 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400808 private void clearSoundLocked() {
809 mSoundNotificationKey = null;
810 long identity = Binder.clearCallingIdentity();
811 try {
812 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
813 if (player != null) {
814 player.stopAsync();
815 }
816 } catch (RemoteException e) {
817 } finally {
818 Binder.restoreCallingIdentity(identity);
819 }
820 }
821
Julia Reynolds88860ce2017-06-01 16:55:49 -0400822 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400823 private void clearVibrateLocked() {
824 mVibrateNotificationKey = null;
825 long identity = Binder.clearCallingIdentity();
826 try {
827 mVibrator.cancel();
828 } finally {
829 Binder.restoreCallingIdentity(identity);
830 }
831 }
832
Julia Reynolds88860ce2017-06-01 16:55:49 -0400833 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400834 private void clearLightsLocked() {
835 // light
836 mLights.clear();
837 updateLightsLocked();
838 }
839
Beverlyd4f96492017-08-02 13:36:11 -0400840 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
841 @Override
842 public void onReceive(Context context, Intent intent) {
843 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
844 mZenModeHelper.updateDefaultZenRules();
Julia Reynolds816797a2017-08-11 15:47:09 -0400845 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400846 }
847 }
848 };
849
Julia Reynoldsb852e562017-06-06 16:14:18 -0400850 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
851 @Override
852 public void onReceive(Context context, Intent intent) {
853 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
854 try {
855 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
856 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100857 int restoredFromSdkInt = intent.getIntExtra(
858 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400859 mListeners.onSettingRestored(
860 element, newValue, restoredFromSdkInt, getSendingUserId());
861 mConditionProviders.onSettingRestored(
862 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400863 } catch (Exception e) {
864 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
865 }
866 }
867 }
868 };
869
Julia Reynolds2a128742016-11-28 14:29:25 -0500870 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
871 @Override
872 public void onReceive(Context context, Intent intent) {
873 String action = intent.getAction();
874 if (action == null) {
875 return;
876 }
877 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
878 final NotificationRecord record;
879 synchronized (mNotificationLock) {
880 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
881 }
882 if (record != null) {
883 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
884 record.sbn.getPackageName(), record.sbn.getTag(),
885 record.sbn.getId(), 0,
886 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
887 REASON_TIMEOUT, null);
888 }
889 }
890 }
891 };
892
Kenny Guy70058402014-10-28 20:45:06 +0000893 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 @Override
895 public void onReceive(Context context, Intent intent) {
896 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -0800897 if (action == null) {
898 return;
899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800901 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -0400902 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -0400903 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -0400904 boolean cancelNotifications = true;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000905 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -0400906
Chris Wren3da73022013-05-10 14:41:21 -0400907 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -0400908 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800909 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -0400910 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800911 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000912 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
913 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +0000914 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
915 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800916 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500917 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -0400918 boolean removingPackage = queryRemove &&
919 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
920 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800921 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800922 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500923 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000924 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
925 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
926 reason = REASON_PACKAGE_SUSPENDED;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800927 } else if (queryRestart) {
928 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500929 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800930 } else {
931 Uri uri = intent.getData();
932 if (uri == null) {
933 return;
934 }
935 String pkgName = uri.getSchemeSpecificPart();
936 if (pkgName == null) {
937 return;
938 }
Daniel Sandler26ece572012-06-01 15:38:46 -0400939 if (packageChanged) {
940 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -0700941 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500942 final int enabled = mPackageManager.getApplicationEnabledSetting(
943 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +0000944 changeUserId != UserHandle.USER_ALL ? changeUserId :
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500945 UserHandle.USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -0700946 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
947 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
948 cancelNotifications = false;
949 }
950 } catch (IllegalArgumentException e) {
951 // Package doesn't exist; probably racing with uninstall.
952 // cancelNotifications is already true, so nothing to do here.
953 if (DBG) {
954 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
955 }
Kenny Guy70058402014-10-28 20:45:06 +0000956 } catch (RemoteException e) {
957 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -0400958 }
959 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800960 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500961 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800963 if (pkgList != null && (pkgList.length > 0)) {
964 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -0400965 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400966 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
967 !queryRestart, changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -0400968 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400971 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400972 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400973 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500974 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
975 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +0000976 }
977 }
978 };
979
980 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
981 @Override
982 public void onReceive(Context context, Intent intent) {
983 String action = intent.getAction();
984
985 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400986 // Keep track of screen on/off state, but do not turn off the notification light
987 // until user passes through the lock screen or views the notification.
988 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +0100989 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400990 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
991 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +0100992 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500993 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -0500994 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
995 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500996 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700997 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
998 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
999 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001000 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001001 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001002 }
Rubin Xue95057a2016-04-01 16:49:25 +01001003 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001004 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001005 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001006 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001007 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001008 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001009 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1010 // turn off LED when user passes through lock screen
1011 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001012 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001013 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001014 // reload per-user settings
1015 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -04001016 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +02001017 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -04001018 mConditionProviders.onUserSwitched(user);
1019 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001020 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -04001021 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001022 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001023 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1024 if (userId != USER_NULL) {
1025 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001026 if (!mUserProfiles.isManagedProfile(userId)) {
1027 readDefaultApprovedServices(userId);
1028 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001029 }
John Spurlock21258a32015-05-27 18:22:55 -04001030 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001031 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
John Spurlock21258a32015-05-27 18:22:55 -04001032 mZenModeHelper.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001033 mRankingHelper.onUserRemoved(user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001034 mListeners.onUserRemoved(user);
1035 mConditionProviders.onUserRemoved(user);
1036 mAssistants.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001037 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001038 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001039 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001040 mConditionProviders.onUserUnlocked(user);
1041 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001042 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001043 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 }
1045 }
1046 };
1047
John Spurlock7c74f782015-06-04 13:01:42 -04001048 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001049 private final Uri NOTIFICATION_BADGING_URI
1050 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001051 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1052 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001053 private final Uri NOTIFICATION_RATE_LIMIT_URI
1054 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001055
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001056 SettingsObserver(Handler handler) {
1057 super(handler);
1058 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001059
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001060 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001061 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001062 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1063 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001064 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001065 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001066 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1067 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001068 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001069 }
1070
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001071 @Override public void onChange(boolean selfChange, Uri uri) {
1072 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001073 }
1074
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001075 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001076 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001077 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001078 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1079 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001080 if (mNotificationPulseEnabled != pulseEnabled) {
1081 mNotificationPulseEnabled = pulseEnabled;
1082 updateNotificationPulse();
1083 }
1084 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001085 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1086 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1087 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1088 }
Chris Wren89aa2262017-05-05 18:05:56 -04001089 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1090 mRankingHelper.updateBadgingEnabled();
1091 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001092 }
1093 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001094
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001095 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001096 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001097
Daniel Sandleredbb3802012-11-13 20:49:47 -08001098 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1099 int[] ar = r.getIntArray(resid);
1100 if (ar == null) {
1101 return def;
1102 }
1103 final int len = ar.length > maxlen ? maxlen : ar.length;
1104 long[] out = new long[len];
1105 for (int i=0; i<len; i++) {
1106 out[i] = ar[i];
1107 }
1108 return out;
1109 }
1110
Jeff Brownb880d882014-02-10 19:47:07 -08001111 public NotificationManagerService(Context context) {
1112 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001113 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001114 }
1115
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001116 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001117 @VisibleForTesting
1118 void setAudioManager(AudioManager audioMananger) {
1119 mAudioManager = audioMananger;
1120 }
1121
1122 @VisibleForTesting
1123 void setVibrator(Vibrator vibrator) {
1124 mVibrator = vibrator;
1125 }
1126
1127 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001128 void setLights(Light light) {
1129 mNotificationLight = light;
1130 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001131 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001132 }
1133
1134 @VisibleForTesting
1135 void setScreenOn(boolean on) {
1136 mScreenOn = on;
1137 }
1138
1139 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001140 int getNotificationRecordCount() {
1141 synchronized (mNotificationLock) {
1142 int count = mNotificationList.size() + mNotificationsByKey.size()
1143 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1144 // subtract duplicates
1145 for (NotificationRecord posted : mNotificationList) {
1146 if (mNotificationsByKey.containsKey(posted.getKey())) {
1147 count--;
1148 }
1149 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001150 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001151 }
1152 }
1153
1154 return count;
1155 }
1156 }
1157
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001158 void clearNotifications() {
1159 mEnqueuedNotifications.clear();
1160 mNotificationList.clear();
1161 mNotificationsByKey.clear();
1162 mSummaryByGroupKey.clear();
1163 }
1164
Julia Reynolds080361e2017-07-13 11:23:12 -04001165 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001166 void addNotification(NotificationRecord r) {
1167 mNotificationList.add(r);
1168 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001169 if (r.sbn.isGroup()) {
1170 mSummaryByGroupKey.put(r.getGroupKey(), r);
1171 }
1172 }
1173
1174 @VisibleForTesting
1175 void addEnqueuedNotification(NotificationRecord r) {
1176 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001177 }
1178
1179 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001180 NotificationRecord getNotificationRecord(String key) {
1181 return mNotificationsByKey.get(key);
1182 }
1183
1184
1185 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001186 void setSystemReady(boolean systemReady) {
1187 mSystemReady = systemReady;
1188 }
1189
1190 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001191 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001192 mHandler = handler;
1193 }
1194
Chris Wrend4054312016-06-24 17:07:40 -04001195 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001196 void setFallbackVibrationPattern(long[] vibrationPattern) {
1197 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001198 }
1199
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001200 @VisibleForTesting
1201 void setPackageManager(IPackageManager packageManager) {
1202 mPackageManager = packageManager;
1203 }
1204
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001205 @VisibleForTesting
1206 void setRankingHelper(RankingHelper rankingHelper) {
1207 mRankingHelper = rankingHelper;
1208 }
1209
1210 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001211 void setRankingHandler(RankingHandler rankingHandler) {
1212 mRankingHandler = rankingHandler;
1213 }
1214
1215 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001216 void setIsTelevision(boolean isTelevision) {
1217 mIsTelevision = isTelevision;
1218 }
1219
Julia Reynolds76c096d2017-06-19 08:16:04 -04001220 @VisibleForTesting
1221 void setUsageStats(NotificationUsageStats us) {
1222 mUsageStats = us;
1223 }
1224
Julia Reynolds94187562017-10-10 13:58:49 -04001225 @VisibleForTesting
1226 void setAccessibilityManager(AccessibilityManager am) {
1227 mAccessibilityManager = am;
1228 }
1229
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001230 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001231 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001232 void init(Looper looper, IPackageManager packageManager,
1233 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001234 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001235 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001236 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001237 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds8aebf352017-06-26 11:35:33 -04001238 ActivityManager activityManager, GroupHelper groupHelper) {
Chris Wren54bbef42014-07-09 18:37:56 -04001239 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001240 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1241 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1242 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1243
Julia Reynolds94187562017-10-10 13:58:49 -04001244 mAccessibilityManager =
1245 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001246 mAm = ActivityManager.getService();
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001247 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001248 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001249 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1250 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001251 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Julia Reynolds2a128742016-11-28 14:29:25 -05001252 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001253 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001254 mActivityManager = activityManager;
San Mehat3ee13172010-02-04 20:54:43 -08001255
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001256 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001257 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001258 String[] extractorNames;
1259 try {
1260 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1261 } catch (Resources.NotFoundException e) {
1262 extractorNames = new String[0];
1263 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001264 mUsageStats = usageStats;
Chris Wren51017d02015-12-15 15:34:46 -05001265 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Chris Wren54bbef42014-07-09 18:37:56 -04001266 mRankingHelper = new RankingHelper(getContext(),
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001267 mPackageManagerClient,
Chris Wren51017d02015-12-15 15:34:46 -05001268 mRankingHandler,
Chris Wren5eab2b72015-06-16 13:56:22 -04001269 mUsageStats,
Chris Wren54bbef42014-07-09 18:37:56 -04001270 extractorNames);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001271 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001272 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001273 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001274 @Override
1275 public void onConfigChanged() {
1276 savePolicyFile();
1277 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001278
1279 @Override
1280 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001281 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001282 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001283 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1284 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001285 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001286 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001287 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001288 }
1289 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001290
1291 @Override
1292 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001293 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1294 }
John Spurlock056c5192014-04-20 21:52:01 -04001295 });
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001296 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001297 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001298
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001299 // This is a ManagedServices object that keeps track of the listeners.
1300 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001301
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001302 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001303 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001304
1305 mPolicyFile = policyFile;
1306 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001307
Adam Lesinski182f73f2013-12-05 16:48:06 -08001308 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001309 if (mStatusBar != null) {
1310 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1311 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001313 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1314 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001315
Daniel Sandleredbb3802012-11-13 20:49:47 -08001316 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001317 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001318 VIBRATE_PATTERN_MAXLEN,
1319 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001320 mInCallNotificationUri = Uri.parse("file://" +
1321 resources.getString(R.string.config_inCallNotificationSound));
1322 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1323 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1324 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001325 .build();
1326 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1327
Chris Wren5116a822014-06-04 15:59:50 -04001328 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1329
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001330 // Don't start allowing notifications until the setup wizard has run once.
1331 // After that, including subsequent boots, init with notifications turned on.
1332 // This works on the first boot because the setup wizard will toggle this
1333 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001334 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001335 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001336 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001337 }
John Spurlockb2278d62015-04-07 12:47:12 -04001338 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001339 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001340
John Spurlockb408e8e2014-04-23 21:12:45 -04001341 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001342 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001343
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001344 mSettingsObserver = new SettingsObserver(mHandler);
1345
1346 mArchive = new Archive(resources.getInteger(
1347 R.integer.config_notificationServiceArchiveSize));
1348
1349 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1350 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1351 }
1352
1353 @Override
1354 public void onStart() {
1355 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1356 @Override
1357 public void repost(int userId, NotificationRecord r) {
1358 try {
1359 if (DBG) {
1360 Slog.d(TAG, "Reposting " + r.getKey());
1361 }
1362 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1363 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1364 r.sbn.getNotification(), userId);
1365 } catch (Exception e) {
1366 Slog.e(TAG, "Cannot un-snooze notification", e);
1367 }
1368 }
1369 }, mUserProfiles);
1370
1371 final File systemDir = new File(Environment.getDataDirectory(), "system");
1372
1373 init(Looper.myLooper(),
1374 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1375 getLocalService(LightsManager.class),
1376 new NotificationListeners(AppGlobals.getPackageManager()),
1377 new NotificationAssistants(AppGlobals.getPackageManager()),
1378 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1379 null, snoozeHelper, new NotificationUsageStats(getContext()),
1380 new AtomicFile(new File(systemDir, "notification_policy.xml")),
1381 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1382 getGroupHelper());
1383
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001384 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001386 filter.addAction(Intent.ACTION_SCREEN_ON);
1387 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001388 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001389 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001390 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001391 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001392 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001393 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001394 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001395 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001396 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001397
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001398 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001399 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001400 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001401 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001402 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1403 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1404 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001405 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1406 null);
1407
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001408 IntentFilter suspendedPkgFilter = new IntentFilter();
1409 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1410 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1411 suspendedPkgFilter, null, null);
1412
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001413 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001414 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1415 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001416
Julia Reynolds2a128742016-11-28 14:29:25 -05001417 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1418 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1419 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1420
Julia Reynoldsb852e562017-06-06 16:14:18 -04001421 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1422 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1423
Beverlyd4f96492017-08-02 13:36:11 -04001424 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1425 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1426
Adam Lesinski182f73f2013-12-05 16:48:06 -08001427 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1428 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 }
1430
Julia Reynolds8aebf352017-06-26 11:35:33 -04001431 private GroupHelper getGroupHelper() {
1432 return new GroupHelper(new GroupHelper.Callback() {
1433 @Override
1434 public void addAutoGroup(String key) {
1435 synchronized (mNotificationLock) {
1436 addAutogroupKeyLocked(key);
1437 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001438 }
1439
1440 @Override
1441 public void removeAutoGroup(String key) {
1442 synchronized (mNotificationLock) {
1443 removeAutogroupKeyLocked(key);
1444 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001445 }
1446
1447 @Override
1448 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1449 createAutoGroupSummary(userId, pkg, triggeringKey);
1450 }
1451
1452 @Override
1453 public void removeAutoGroupSummary(int userId, String pkg) {
1454 synchronized (mNotificationLock) {
1455 clearAutogroupSummaryLocked(userId, pkg);
1456 }
1457 }
1458 });
1459 }
1460
John Spurlocke7a835b2015-05-13 10:47:05 -04001461 private void sendRegisteredOnlyBroadcast(String action) {
1462 getContext().sendBroadcastAsUser(new Intent(action)
1463 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1464 }
1465
Adam Lesinski182f73f2013-12-05 16:48:06 -08001466 @Override
1467 public void onBootPhase(int phase) {
1468 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1469 // no beeping until we're basically done booting
1470 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001471
Adam Lesinski182f73f2013-12-05 16:48:06 -08001472 // Grab our optional AudioService
1473 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001474 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001475 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001476 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001477 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1478 // This observer will force an update when observe is called, causing us to
1479 // bind to listener services.
1480 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001481 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001482 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001483 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001484 }
1485 }
1486
Julia Reynolds88860ce2017-06-01 16:55:49 -04001487 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001488 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001489 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001490 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001491 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001492 mListenerHints = hints;
1493 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001494 }
1495
Julia Reynolds88860ce2017-06-01 16:55:49 -04001496 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001497 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001498 final long updatedSuppressedEffects = calculateSuppressedEffects();
1499 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1500 final List<ComponentName> suppressors = getSuppressors();
1501 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1502 mEffectsSuppressors = suppressors;
1503 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001504 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001505 }
1506
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001507 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1508 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001509 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1510 // cancel
1511 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001512 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001513 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001514 if (isUidSystemOrPhone(uid)) {
1515 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1516 int N = profileIds.length;
1517 for (int i = 0; i < N; i++) {
1518 int profileId = profileIds[i];
1519 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1520 profileId, REASON_CHANNEL_BANNED,
1521 null);
1522 }
1523 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001524 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001525 final NotificationChannel preUpdate =
1526 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1527
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001528 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001529 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001530
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001531 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001532 final NotificationChannel modifiedChannel =
1533 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001534 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001535 pkg, UserHandle.getUserHandleForUid(uid),
1536 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001537 }
1538
Julia Reynolds924eed12017-01-19 09:52:07 -05001539 savePolicyFile();
1540 }
1541
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001542 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1543 NotificationChannel update) {
1544 try {
1545 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1546 && update.getImportance() != IMPORTANCE_NONE)
1547 || (preUpdate.getImportance() != IMPORTANCE_NONE
1548 && update.getImportance() == IMPORTANCE_NONE)) {
1549 getContext().sendBroadcastAsUser(
1550 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
1551 .putExtra(NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID,
1552 update.getId())
1553 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1554 update.getImportance() == IMPORTANCE_NONE)
1555 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1556 .setPackage(pkg),
1557 UserHandle.of(UserHandle.getUserId(uid)), null);
1558 }
1559 } catch (SecurityException e) {
1560 Slog.w(TAG, "Can't notify app about channel change", e);
1561 }
1562 }
1563
Julia Reynolds005c8b92017-08-24 10:35:53 -04001564 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1565 boolean fromApp, boolean fromListener) {
1566 Preconditions.checkNotNull(group);
1567 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001568
1569 final NotificationChannelGroup preUpdate =
1570 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001571 mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1572 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001573 if (!fromApp) {
1574 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1575 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001576 if (!fromListener) {
1577 mListeners.notifyNotificationChannelGroupChanged(pkg,
1578 UserHandle.of(UserHandle.getCallingUserId()), group,
1579 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1580 }
1581 }
1582
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001583 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1584 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1585 try {
1586 if (preUpdate.isBlocked() != update.isBlocked()) {
1587 getContext().sendBroadcastAsUser(
1588 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
1589 .putExtra(NotificationManager.EXTRA_BLOCK_STATE_CHANGED_ID,
1590 update.getId())
1591 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1592 update.isBlocked())
1593 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1594 .setPackage(pkg),
1595 UserHandle.of(UserHandle.getUserId(uid)), null);
1596 }
1597 } catch (SecurityException e) {
1598 Slog.w(TAG, "Can't notify app about group change", e);
1599 }
1600 }
1601
Bryce Lee7219ada2016-04-08 10:54:23 -07001602 private ArrayList<ComponentName> getSuppressors() {
1603 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1604 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1605 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1606
1607 for (ManagedServiceInfo info : serviceInfoList) {
1608 names.add(info.component);
1609 }
1610 }
1611
1612 return names;
1613 }
1614
1615 private boolean removeDisabledHints(ManagedServiceInfo info) {
1616 return removeDisabledHints(info, 0);
1617 }
1618
1619 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1620 boolean removed = false;
1621
1622 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1623 final int hint = mListenersDisablingEffects.keyAt(i);
1624 final ArraySet<ManagedServiceInfo> listeners =
1625 mListenersDisablingEffects.valueAt(i);
1626
1627 if (hints == 0 || (hint & hints) == hint) {
1628 removed = removed || listeners.remove(info);
1629 }
1630 }
1631
1632 return removed;
1633 }
1634
1635 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1636 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1637 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1638 }
1639
1640 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1641 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1642 }
1643
1644 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1645 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1646 }
1647 }
1648
1649 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1650 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1651 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1652 }
1653
1654 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1655 hintListeners.add(info);
1656 }
1657
1658 private int calculateHints() {
1659 int hints = 0;
1660 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1661 int hint = mListenersDisablingEffects.keyAt(i);
1662 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1663
1664 if (!serviceInfoList.isEmpty()) {
1665 hints |= hint;
1666 }
1667 }
1668
1669 return hints;
1670 }
1671
1672 private long calculateSuppressedEffects() {
1673 int hints = calculateHints();
1674 long suppressedEffects = 0;
1675
1676 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1677 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1678 }
1679
1680 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1681 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1682 }
1683
1684 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1685 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1686 }
1687
1688 return suppressedEffects;
1689 }
1690
Julia Reynolds88860ce2017-06-01 16:55:49 -04001691 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001692 private void updateInterruptionFilterLocked() {
1693 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1694 if (interruptionFilter == mInterruptionFilter) return;
1695 mInterruptionFilter = interruptionFilter;
1696 scheduleInterruptionFilterChanged(interruptionFilter);
1697 }
1698
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001699 @VisibleForTesting
1700 INotificationManager getBinderService() {
1701 return INotificationManager.Stub.asInterface(mService);
1702 }
1703
Amith Yamasani803eab692017-11-09 17:47:04 -08001704 protected void reportSeen(NotificationRecord r) {
1705 final int userId = r.sbn.getUserId();
1706 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1707 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
1708 : userId,
1709 UsageEvents.Event.NOTIFICATION_SEEN);
1710 }
1711
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001712 @VisibleForTesting
1713 NotificationManagerInternal getInternalService() {
1714 return mInternalService;
1715 }
1716
Adam Lesinski182f73f2013-12-05 16:48:06 -08001717 private final IBinder mService = new INotificationManager.Stub() {
1718 // Toasts
1719 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001721 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001722 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001723 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001724 if (DBG) {
1725 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1726 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001727 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001728
1729 if (pkg == null || callback == null) {
1730 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1731 return ;
1732 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001733 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001734 final boolean isPackageSuspended =
1735 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001736
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001737 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001738 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1739 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001740 Slog.e(TAG, "Suppressing toast from package " + pkg
1741 + (isPackageSuspended
1742 ? " due to package suspended by administrator."
1743 : " by user request."));
1744 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001745 }
1746
1747 synchronized (mToastQueue) {
1748 int callingPid = Binder.getCallingPid();
1749 long callingId = Binder.clearCallingIdentity();
1750 try {
1751 ToastRecord record;
Beverly4ee785b2017-08-11 12:49:56 -04001752 int index;
1753 // All packages aside from the android package can enqueue one toast at a time
1754 if (!isSystemToast) {
1755 index = indexOfToastPackageLocked(pkg);
1756 } else {
1757 index = indexOfToastLocked(pkg, callback);
1758 }
1759
1760 // If the package already has a toast, we update its toast
1761 // in the queue, we don't move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001762 if (index >= 0) {
1763 record = mToastQueue.get(index);
1764 record.update(duration);
Beverly4ee785b2017-08-11 12:49:56 -04001765 record.update(callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001766 } else {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001767 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07001768 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001769 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001770 mToastQueue.add(record);
1771 index = mToastQueue.size() - 1;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001772 }
Beverly4ee785b2017-08-11 12:49:56 -04001773 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001774 // If it's at index 0, it's the current toast. It doesn't matter if it's
1775 // new or just been updated. Call back and tell it to show itself.
1776 // If the callback fails, this will remove it from the list, so don't
1777 // assume that it's valid after this.
1778 if (index == 0) {
1779 showNextToastLocked();
1780 }
1781 } finally {
1782 Binder.restoreCallingIdentity(callingId);
1783 }
1784 }
1785 }
1786
1787 @Override
1788 public void cancelToast(String pkg, ITransientNotification callback) {
1789 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1790
1791 if (pkg == null || callback == null) {
1792 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1793 return ;
1794 }
1795
1796 synchronized (mToastQueue) {
1797 long callingId = Binder.clearCallingIdentity();
1798 try {
1799 int index = indexOfToastLocked(pkg, callback);
1800 if (index >= 0) {
1801 cancelToastLocked(index);
1802 } else {
1803 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1804 + " callback=" + callback);
1805 }
1806 } finally {
1807 Binder.restoreCallingIdentity(callingId);
1808 }
1809 }
1810 }
1811
1812 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001813 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001814 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001815 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001816 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001817 }
1818
1819 @Override
1820 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001821 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001822 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1823 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04001824 // Don't allow client applications to cancel foreground service notis or autobundled
1825 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001826 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1827 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04001828 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001829 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001830 }
1831
1832 @Override
1833 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001834 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001835
1836 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1837 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1838
1839 // Calling from user space, don't allow the canceling of actively
1840 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04001841 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001842 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001843 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001844 }
1845
1846 @Override
1847 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
John Spurlock7340fc82014-04-24 18:50:12 -04001848 checkCallerIsSystem();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001849
Chris Wrenacf424a2016-03-15 12:48:55 -04001850 mRankingHelper.setEnabled(pkg, uid, enabled);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001851 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04001852 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001853 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1854 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1855 }
Chris Wrenacf424a2016-03-15 12:48:55 -04001856 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001857 }
1858
1859 /**
1860 * Use this when you just want to know if notifications are OK for this package.
1861 */
1862 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001863 public boolean areNotificationsEnabled(String pkg) {
1864 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1865 }
1866
1867 /**
1868 * Use this when you just want to know if notifications are OK for this package.
1869 */
1870 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001871 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001872 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001873
1874 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001875 }
1876
Chris Wren54bbef42014-07-09 18:37:56 -04001877 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001878 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001879 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05001880 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001881 }
1882
1883 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05001884 public boolean canShowBadge(String pkg, int uid) {
1885 checkCallerIsSystem();
1886 return mRankingHelper.canShowBadge(pkg, uid);
1887 }
1888
1889 @Override
1890 public void setShowBadge(String pkg, int uid, boolean showBadge) {
1891 checkCallerIsSystem();
1892 mRankingHelper.setShowBadge(pkg, uid, showBadge);
1893 savePolicyFile();
1894 }
1895
1896 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04001897 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
1898 NotificationChannelGroup group) throws RemoteException {
1899 enforceSystemOrSystemUI("Caller not system or systemui");
1900 createNotificationChannelGroup(pkg, uid, group, false, false);
1901 savePolicyFile();
1902 }
1903
1904 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05001905 public void createNotificationChannelGroups(String pkg,
1906 ParceledListSlice channelGroupList) throws RemoteException {
1907 checkCallerIsSystemOrSameApp(pkg);
1908 List<NotificationChannelGroup> groups = channelGroupList.getList();
1909 final int groupSize = groups.size();
1910 for (int i = 0; i < groupSize; i++) {
1911 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001912 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05001913 }
1914 savePolicyFile();
1915 }
1916
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001917 private void createNotificationChannelsImpl(String pkg, int uid,
1918 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001919 List<NotificationChannel> channels = channelsList.getList();
1920 final int channelsSize = channels.size();
1921 for (int i = 0; i < channelsSize; i++) {
1922 final NotificationChannel channel = channels.get(i);
1923 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001924 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001925 true /* fromTargetApp */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001926 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001927 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001928 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1929 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001930 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001931 savePolicyFile();
1932 }
1933
1934 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001935 public void createNotificationChannels(String pkg,
1936 ParceledListSlice channelsList) throws RemoteException {
1937 checkCallerIsSystemOrSameApp(pkg);
1938 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1939 }
1940
1941 @Override
1942 public void createNotificationChannelsForPackage(String pkg, int uid,
1943 ParceledListSlice channelsList) throws RemoteException {
1944 checkCallerIsSystem();
1945 createNotificationChannelsImpl(pkg, uid, channelsList);
1946 }
1947
1948 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001949 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001950 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001951 return mRankingHelper.getNotificationChannel(
1952 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001953 }
1954
1955 @Override
1956 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001957 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001958 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04001959 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001960 }
1961
1962 @Override
1963 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001964 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001965 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001966 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1967 throw new IllegalArgumentException("Cannot delete default channel");
1968 }
1969 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001970 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1971 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1972 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001973 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001974 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1975 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001976 savePolicyFile();
1977 }
1978
1979 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001980 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
1981 checkCallerIsSystemOrSameApp(pkg);
1982 return mRankingHelper.getNotificationChannelGroupWithChannels(
1983 pkg, Binder.getCallingUid(), groupId, false);
1984 }
1985
1986 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04001987 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1988 String pkg) {
1989 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001990 return mRankingHelper.getNotificationChannelGroups(
1991 pkg, Binder.getCallingUid(), false, false);
Julia Reynolds9bfba592017-03-15 14:03:55 -04001992 }
1993
1994 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001995 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04001996 checkCallerIsSystemOrSameApp(pkg);
1997
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001998 final int callingUid = Binder.getCallingUid();
1999 NotificationChannelGroup groupToDelete =
2000 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2001 if (groupToDelete != null) {
2002 List<NotificationChannel> deletedChannels =
2003 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2004 for (int i = 0; i < deletedChannels.size(); i++) {
2005 final NotificationChannel deletedChannel = deletedChannels.get(i);
2006 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2007 true,
2008 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2009 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002010 mListeners.notifyNotificationChannelChanged(pkg,
2011 UserHandle.getUserHandleForUid(callingUid),
2012 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002013 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2014 }
2015 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002016 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2017 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002018 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002019 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002020 }
2021
2022 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002023 public void updateNotificationChannelForPackage(String pkg, int uid,
2024 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002025 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002026 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002027 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002028 }
2029
2030 @Override
2031 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002032 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002033 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002034 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002035 }
2036
2037 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002038 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2039 boolean includeDeleted) {
2040 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2041 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2042 .getList().size();
2043 }
2044
2045 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002046 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2047 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2048 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2049 }
2050
2051 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002052 public int getDeletedChannelCount(String pkg, int uid) {
2053 enforceSystemOrSystemUI("getDeletedChannelCount");
2054 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2055 }
2056
2057 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002058 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2059 String pkg, int uid, boolean includeDeleted) {
2060 checkCallerIsSystem();
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002061 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002062 }
2063
2064 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002065 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2066 String pkg, int uid, String groupId, boolean includeDeleted) {
2067 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2068 return mRankingHelper.getNotificationChannelGroupWithChannels(
2069 pkg, uid, groupId, includeDeleted);
2070 }
2071
2072 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002073 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2074 String groupId, String pkg, int uid) {
2075 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2076 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2077 }
2078
2079 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002080 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2081 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002082 return mRankingHelper.getNotificationChannels(
2083 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002084 }
2085
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002086 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002087 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002088 checkCallerIsSystem();
2089
2090 // Cancel posted notifications
2091 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2092 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2093
Julia Reynoldsb852e562017-06-06 16:14:18 -04002094 final String[] packages = new String[] {packageName};
2095 final int[] uids = new int[] {uid};
2096
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002097 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002098 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002099 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002100
2101 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002102 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002103
2104 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002105 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002106 mRankingHelper.onPackagesChanged(
2107 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002108 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002109
2110 savePolicyFile();
2111 }
2112
2113
Adam Lesinski182f73f2013-12-05 16:48:06 -08002114 /**
2115 * System-only API for getting a list of current (i.e. not cleared) notifications.
2116 *
2117 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002118 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002119 */
2120 @Override
2121 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2122 // enforce() will ensure the calling uid has the correct permission
2123 getContext().enforceCallingOrSelfPermission(
2124 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2125 "NotificationManagerService.getActiveNotifications");
2126
2127 StatusBarNotification[] tmp = null;
2128 int uid = Binder.getCallingUid();
2129
2130 // noteOp will check to make sure the callingPkg matches the uid
2131 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2132 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002133 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002134 tmp = new StatusBarNotification[mNotificationList.size()];
2135 final int N = mNotificationList.size();
2136 for (int i=0; i<N; i++) {
2137 tmp[i] = mNotificationList.get(i).sbn;
2138 }
2139 }
2140 }
2141 return tmp;
2142 }
2143
2144 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002145 * Public API for getting a list of current notifications for the calling package/uid.
2146 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002147 * Note that since notification posting is done asynchronously, this will not return
2148 * notifications that are in the process of being posted.
2149 *
Dan Sandler994349c2015-04-15 11:02:54 -04002150 * @returns A list of all the package's notifications, in natural order.
2151 */
2152 @Override
2153 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2154 int incomingUserId) {
2155 checkCallerIsSystemOrSameApp(pkg);
2156 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2157 Binder.getCallingUid(), incomingUserId, true, false,
2158 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002159 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002160 final ArrayMap<String, StatusBarNotification> map
2161 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002162 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002163 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002164 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2165 mNotificationList.get(i).sbn);
2166 if (sbn != null) {
2167 map.put(sbn.getKey(), sbn);
2168 }
2169 }
2170 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2171 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2172 if (sbn != null) {
2173 map.put(sbn.getKey(), sbn);
2174 }
2175 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002176 final int M = mEnqueuedNotifications.size();
2177 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002178 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2179 mEnqueuedNotifications.get(i).sbn);
2180 if (sbn != null) {
2181 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002182 }
2183 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002184 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2185 list.addAll(map.values());
2186 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002187 }
Dan Sandler994349c2015-04-15 11:02:54 -04002188 }
2189
Chris Wren6676dab2016-12-21 18:26:27 -05002190 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2191 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002192 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002193 // We could pass back a cloneLight() but clients might get confused and
2194 // try to send this thing back to notify() again, which would not work
2195 // very well.
2196 return new StatusBarNotification(
2197 sbn.getPackageName(),
2198 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002199 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2200 sbn.getNotification().clone(),
2201 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2202 }
2203 return null;
2204 }
2205
Dan Sandler994349c2015-04-15 11:02:54 -04002206 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002207 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2208 *
2209 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2210 */
2211 @Override
2212 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2213 // enforce() will ensure the calling uid has the correct permission
2214 getContext().enforceCallingOrSelfPermission(
2215 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2216 "NotificationManagerService.getHistoricalNotifications");
2217
2218 StatusBarNotification[] tmp = null;
2219 int uid = Binder.getCallingUid();
2220
2221 // noteOp will check to make sure the callingPkg matches the uid
2222 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2223 == AppOpsManager.MODE_ALLOWED) {
2224 synchronized (mArchive) {
2225 tmp = mArchive.getArray(count);
2226 }
2227 }
2228 return tmp;
2229 }
2230
2231 /**
2232 * Register a listener binder directly with the notification manager.
2233 *
2234 * Only works with system callers. Apps should extend
2235 * {@link android.service.notification.NotificationListenerService}.
2236 */
2237 @Override
2238 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002239 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002240 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002241 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002242 }
2243
2244 /**
2245 * Remove a listener binder directly
2246 */
2247 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002248 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002249 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002250 }
2251
2252 /**
2253 * Allow an INotificationListener to simulate a "clear all" operation.
2254 *
2255 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2256 *
2257 * @param token The binder for the listener, to check that the caller is allowed
2258 */
2259 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002260 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002261 final int callingUid = Binder.getCallingUid();
2262 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002263 long identity = Binder.clearCallingIdentity();
2264 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002265 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002266 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
John Spurlocka4294292014-03-24 18:02:32 -04002267 if (keys != null) {
2268 final int N = keys.length;
2269 for (int i = 0; i < N; i++) {
2270 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002271 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002272 final int userId = r.sbn.getUserId();
2273 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002274 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002275 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002276 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002277 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002278 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2279 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2280 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002281 }
2282 } else {
2283 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002284 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002285 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002286 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002287 } finally {
2288 Binder.restoreCallingIdentity(identity);
2289 }
2290 }
2291
Chris Wrenab41eec2016-01-04 18:01:27 -05002292 /**
2293 * Handle request from an approved listener to re-enable itself.
2294 *
2295 * @param component The componenet to be re-enabled, caller must match package.
2296 */
2297 @Override
2298 public void requestBindListener(ComponentName component) {
2299 checkCallerIsSystemOrSameApp(component.getPackageName());
2300 long identity = Binder.clearCallingIdentity();
2301 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002302 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002303 mAssistants.isComponentEnabledForCurrentProfiles(component)
2304 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002305 : mListeners;
2306 manager.setComponentState(component, true);
2307 } finally {
2308 Binder.restoreCallingIdentity(identity);
2309 }
2310 }
2311
2312 @Override
2313 public void requestUnbindListener(INotificationListener token) {
2314 long identity = Binder.clearCallingIdentity();
2315 try {
2316 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002317 synchronized (mNotificationLock) {
2318 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2319 info.getOwner().setComponentState(info.component, false);
2320 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002321 } finally {
2322 Binder.restoreCallingIdentity(identity);
2323 }
2324 }
2325
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002326 @Override
2327 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002328 long identity = Binder.clearCallingIdentity();
2329 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002330 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002331 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2332 if (keys != null) {
2333 final int N = keys.length;
2334 for (int i = 0; i < N; i++) {
2335 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2336 if (r == null) continue;
2337 final int userId = r.sbn.getUserId();
2338 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2339 !mUserProfiles.isCurrentProfile(userId)) {
2340 throw new SecurityException("Disallowed call from listener: "
2341 + info.service);
2342 }
2343 if (!r.isSeen()) {
2344 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002345 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002346 r.setSeen();
2347 }
2348 }
2349 }
2350 }
2351 } finally {
2352 Binder.restoreCallingIdentity(identity);
2353 }
2354 }
2355
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002356 /**
2357 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2358 *
2359 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2360 *
Julia Reynolds79672302017-01-12 08:30:16 -05002361 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002362 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002363 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002364 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002365 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002366 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2367 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2368 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002369 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002370 }
2371
Adam Lesinski182f73f2013-12-05 16:48:06 -08002372 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002373 * Allow an INotificationListener to snooze a single notification until a context.
2374 *
2375 * @param token The binder for the listener, to check that the caller is allowed
2376 */
2377 @Override
2378 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2379 String key, String snoozeCriterionId) {
2380 long identity = Binder.clearCallingIdentity();
2381 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002382 synchronized (mNotificationLock) {
2383 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2384 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2385 }
Julia Reynolds79672302017-01-12 08:30:16 -05002386 } finally {
2387 Binder.restoreCallingIdentity(identity);
2388 }
2389 }
2390
2391 /**
2392 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002393 *
2394 * @param token The binder for the listener, to check that the caller is allowed
2395 */
2396 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002397 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002398 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002399 long identity = Binder.clearCallingIdentity();
2400 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002401 synchronized (mNotificationLock) {
2402 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2403 snoozeNotificationInt(key, duration, null, info);
2404 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002405 } finally {
2406 Binder.restoreCallingIdentity(identity);
2407 }
2408 }
2409
2410 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002411 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002412 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002413 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002414 */
2415 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002416 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002417 long identity = Binder.clearCallingIdentity();
2418 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002419 synchronized (mNotificationLock) {
2420 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002421 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002422 unsnoozeNotificationInt(key, info);
2423 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002424 } finally {
2425 Binder.restoreCallingIdentity(identity);
2426 }
2427 }
2428
2429 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002430 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2431 *
2432 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2433 *
2434 * @param token The binder for the listener, to check that the caller is allowed
2435 */
2436 @Override
2437 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2438 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002439 final int callingUid = Binder.getCallingUid();
2440 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002441 long identity = Binder.clearCallingIdentity();
2442 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002443 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002444 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002445 if (info.supportsProfiles()) {
2446 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2447 + "from " + info.component
2448 + " use cancelNotification(key) instead.");
2449 } else {
2450 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2451 pkg, tag, id, info.userid);
2452 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002453 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002454 } finally {
2455 Binder.restoreCallingIdentity(identity);
2456 }
2457 }
2458
2459 /**
2460 * Allow an INotificationListener to request the list of outstanding notifications seen by
2461 * the current user. Useful when starting up, after which point the listener callbacks
2462 * should be used.
2463 *
2464 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002465 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002466 * @returns The return value will contain the notifications specified in keys, in that
2467 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002468 */
2469 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002470 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002471 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002472 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002473 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002474 final boolean getKeys = keys != null;
2475 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002476 final ArrayList<StatusBarNotification> list
2477 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002478 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002479 final NotificationRecord r = getKeys
2480 ? mNotificationsByKey.get(keys[i])
2481 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002482 if (r == null) continue;
2483 StatusBarNotification sbn = r.sbn;
2484 if (!isVisibleToListener(sbn, info)) continue;
2485 StatusBarNotification sbnToSend =
2486 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2487 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002488 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002489 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002490 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002491 }
2492
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002493 /**
2494 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2495 * seen by the current user. Useful when starting up, after which point the listener
2496 * callbacks should be used.
2497 *
2498 * @param token The binder for the listener, to check that the caller is allowed
2499 * @returns The return value will contain the notifications specified in keys, in that
2500 * order, or if keys is null, all the notifications, in natural order.
2501 */
2502 @Override
2503 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2504 INotificationListener token, int trim) {
2505 synchronized (mNotificationLock) {
2506 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2507 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2508 final int N = snoozedRecords.size();
2509 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2510 for (int i=0; i < N; i++) {
2511 final NotificationRecord r = snoozedRecords.get(i);
2512 if (r == null) continue;
2513 StatusBarNotification sbn = r.sbn;
2514 if (!isVisibleToListener(sbn, info)) continue;
2515 StatusBarNotification sbnToSend =
2516 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2517 list.add(sbnToSend);
2518 }
2519 return new ParceledListSlice<>(list);
2520 }
2521 }
2522
Adam Lesinski182f73f2013-12-05 16:48:06 -08002523 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002524 public void requestHintsFromListener(INotificationListener token, int hints) {
2525 final long identity = Binder.clearCallingIdentity();
2526 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002527 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002528 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002529 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2530 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2531 | HINT_HOST_DISABLE_CALL_EFFECTS;
2532 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002533 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002534 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002535 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002536 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002537 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002538 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002539 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002540 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002541 } finally {
2542 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002543 }
2544 }
2545
2546 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002547 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002548 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002549 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002550 }
2551 }
2552
2553 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002554 public void requestInterruptionFilterFromListener(INotificationListener token,
2555 int interruptionFilter) throws RemoteException {
2556 final long identity = Binder.clearCallingIdentity();
2557 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002558 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002559 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2560 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002561 updateInterruptionFilterLocked();
2562 }
2563 } finally {
2564 Binder.restoreCallingIdentity(identity);
2565 }
2566 }
2567
2568 @Override
2569 public int getInterruptionFilterFromListener(INotificationListener token)
2570 throws RemoteException {
2571 synchronized (mNotificationLight) {
2572 return mInterruptionFilter;
2573 }
2574 }
2575
2576 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002577 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2578 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002579 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002580 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2581 if (info == null) return;
2582 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2583 }
2584 }
2585
2586 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002587 public int getZenMode() {
2588 return mZenModeHelper.getZenMode();
2589 }
2590
2591 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002592 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002593 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002594 return mZenModeHelper.getConfig();
2595 }
2596
2597 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002598 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002599 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002600 final long identity = Binder.clearCallingIdentity();
2601 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002602 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002603 } finally {
2604 Binder.restoreCallingIdentity(identity);
2605 }
2606 }
2607
2608 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002609 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002610 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002611 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002612 }
2613
2614 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002615 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2616 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002617 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002618 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002619 }
2620
2621 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002622 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002623 throws RemoteException {
2624 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2625 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2626 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2627 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002628 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002629
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002630 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2631 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002632 }
2633
2634 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002635 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002636 throws RemoteException {
2637 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2638 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2639 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2640 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2641 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002642
Julia Reynolds361e82d32016-02-26 18:19:49 -05002643 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002644 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002645 }
2646
2647 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002648 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2649 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002650 // Verify that they can modify zen rules.
2651 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2652
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002653 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002654 }
2655
2656 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05002657 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2658 Preconditions.checkNotNull(packageName, "Package name is null");
2659 enforceSystemOrSystemUI("removeAutomaticZenRules");
2660
2661 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2662 }
2663
2664 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05002665 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2666 Preconditions.checkNotNull(owner, "Owner is null");
2667 enforceSystemOrSystemUI("getRuleInstanceCount");
2668
2669 return mZenModeHelper.getCurrentInstanceCount(owner);
2670 }
2671
2672 @Override
John Spurlock80774932015-05-07 17:38:50 -04002673 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2674 enforcePolicyAccess(pkg, "setInterruptionFilter");
2675 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2676 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2677 final long identity = Binder.clearCallingIdentity();
2678 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002679 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04002680 } finally {
2681 Binder.restoreCallingIdentity(identity);
2682 }
2683 }
2684
2685 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04002686 public void notifyConditions(final String pkg, IConditionProvider provider,
2687 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04002688 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2689 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04002690 mHandler.post(new Runnable() {
2691 @Override
2692 public void run() {
2693 mConditionProviders.notifyConditions(pkg, info, conditions);
2694 }
2695 });
John Spurlocke77bb362014-04-26 10:24:59 -04002696 }
2697
Julia Reynolds38e6ca42016-08-08 08:38:09 -04002698 @Override
2699 public void requestUnbindProvider(IConditionProvider provider) {
2700 long identity = Binder.clearCallingIdentity();
2701 try {
2702 // allow bound services to disable themselves
2703 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2704 info.getOwner().setComponentState(info.component, false);
2705 } finally {
2706 Binder.restoreCallingIdentity(identity);
2707 }
2708 }
2709
2710 @Override
2711 public void requestBindProvider(ComponentName component) {
2712 checkCallerIsSystemOrSameApp(component.getPackageName());
2713 long identity = Binder.clearCallingIdentity();
2714 try {
2715 mConditionProviders.setComponentState(component, true);
2716 } finally {
2717 Binder.restoreCallingIdentity(identity);
2718 }
2719 }
2720
John Spurlocke77bb362014-04-26 10:24:59 -04002721 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002722 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04002723 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2724 message);
John Spurlock7340fc82014-04-24 18:50:12 -04002725 }
2726
Julia Reynolds48034f82016-03-09 10:15:16 -05002727 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2728 try {
2729 checkCallerIsSystemOrSameApp(pkg);
2730 } catch (SecurityException e) {
2731 getContext().enforceCallingPermission(
2732 android.Manifest.permission.STATUS_BAR_SERVICE,
2733 message);
2734 }
2735 }
2736
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002737 private void enforcePolicyAccess(int uid, String method) {
2738 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2739 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2740 return;
2741 }
2742 boolean accessAllowed = false;
2743 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2744 final int packageCount = packages.length;
2745 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002746 if (mConditionProviders.isPackageOrComponentAllowed(
2747 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002748 accessAllowed = true;
2749 }
2750 }
2751 if (!accessAllowed) {
2752 Slog.w(TAG, "Notification policy access denied calling " + method);
2753 throw new SecurityException("Notification policy access denied");
2754 }
2755 }
2756
John Spurlock80774932015-05-07 17:38:50 -04002757 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04002758 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2759 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2760 return;
2761 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04002762 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002763 if (!checkPolicyAccess(pkg)) {
2764 Slog.w(TAG, "Notification policy access denied calling " + method);
2765 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04002766 }
2767 }
2768
John Spurlock80774932015-05-07 17:38:50 -04002769 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002770 return mConditionProviders.isPackageOrComponentAllowed(
2771 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04002772 }
2773
2774 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04002775 try {
2776 int uid = getContext().getPackageManager().getPackageUidAsUser(
2777 pkg, UserHandle.getCallingUserId());
2778 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2779 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2780 -1, true)) {
2781 return true;
2782 }
2783 } catch (NameNotFoundException e) {
2784 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002785 }
John Spurlock80774932015-05-07 17:38:50 -04002786 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002787 }
2788
John Spurlock7340fc82014-04-24 18:50:12 -04002789 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002790 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002791 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04002792 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Kweku Adams887f09c2017-11-13 17:12:20 -08002793 if (filter.stats) {
Chris Wrene4b38802015-07-07 15:54:19 -04002794 dumpJson(pw, filter);
Kweku Adams887f09c2017-11-13 17:12:20 -08002795 } else if (filter.proto) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05002796 dumpProto(fd, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04002797 } else {
2798 dumpImpl(pw, filter);
2799 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002800 }
John Spurlockb4782522014-08-22 14:54:46 -04002801
2802 @Override
2803 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07002804 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04002805 }
John Spurlock2b122f42014-08-27 16:29:47 -04002806
2807 @Override
2808 public boolean matchesCallFilter(Bundle extras) {
2809 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02002810 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002811 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02002812 extras,
2813 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2814 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2815 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04002816 }
John Spurlock530052a2014-11-30 16:26:19 -05002817
2818 @Override
2819 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002820 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04002821 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05002822 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002823
Christopher Tatef9767d62015-04-08 14:35:43 -07002824 // Backup/restore interface
2825 @Override
2826 public byte[] getBackupPayload(int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002827 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002828 //TODO: http://b/22388012
2829 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002830 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2831 return null;
2832 }
songjinshi9bf22712017-02-04 10:47:45 +08002833 synchronized(mPolicyFile) {
2834 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2835 try {
2836 writePolicyXml(baos, true /*forBackup*/);
2837 return baos.toByteArray();
2838 } catch (IOException e) {
2839 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2840 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002841 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002842 return null;
2843 }
2844
2845 @Override
2846 public void applyRestore(byte[] payload, int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002847 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2848 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2849 if (payload == null) {
2850 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2851 return;
2852 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002853 //TODO: http://b/22388012
2854 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002855 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2856 return;
2857 }
songjinshi9bf22712017-02-04 10:47:45 +08002858 synchronized(mPolicyFile) {
2859 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2860 try {
2861 readPolicyXml(bais, true /*forRestore*/);
2862 savePolicyFile();
2863 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2864 Slog.w(TAG, "applyRestore: error reading payload", e);
2865 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002866 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002867 }
2868
John Spurlock1fc476d2015-04-14 16:05:20 -04002869 @Override
John Spurlock80774932015-05-07 17:38:50 -04002870 public boolean isNotificationPolicyAccessGranted(String pkg) {
2871 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002872 }
2873
2874 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05002875 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2876 enforceSystemOrSystemUIOrSamePackage(pkg,
2877 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002878 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002879 }
2880
2881 @Override
John Spurlock80774932015-05-07 17:38:50 -04002882 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2883 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04002884 setNotificationPolicyAccessGrantedForUser(
2885 pkg, getCallingUserHandle().getIdentifier(), granted);
2886 }
2887
2888 @Override
2889 public void setNotificationPolicyAccessGrantedForUser(
2890 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002891 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04002892 final long identity = Binder.clearCallingIdentity();
2893 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04002894 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04002895 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04002896 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002897
Julia Reynoldse5c680f2017-09-13 09:25:10 -04002898 getContext().sendBroadcastAsUser(new Intent(
2899 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2900 .setPackage(pkg)
2901 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04002902 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04002903 savePolicyFile();
2904 }
2905 } finally {
2906 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04002907 }
John Spurlock80774932015-05-07 17:38:50 -04002908 }
2909
2910 @Override
2911 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04002912 final long identity = Binder.clearCallingIdentity();
2913 try {
2914 return mZenModeHelper.getNotificationPolicy();
2915 } finally {
2916 Binder.restoreCallingIdentity(identity);
2917 }
2918 }
2919
Beverly6697eff2017-12-14 15:00:27 -05002920 /**
2921 * Sets the notification policy. Apps that target API levels below
2922 * {@link android.os.Build.VERSION_CODES#P} cannot make DND silence
2923 * {@link Policy#PRIORITY_CATEGORY_ALARMS} or
2924 * {@link Policy#PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER}
2925 */
John Spurlock1fc476d2015-04-14 16:05:20 -04002926 @Override
John Spurlock80774932015-05-07 17:38:50 -04002927 public void setNotificationPolicy(String pkg, Policy policy) {
2928 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002929 final long identity = Binder.clearCallingIdentity();
2930 try {
Beverly6697eff2017-12-14 15:00:27 -05002931 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
2932 0, UserHandle.getUserId(MY_UID));
2933
2934 if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
2935 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
2936
2937 int priorityCategories = policy.priorityCategories
2938 | (currPolicy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS)
2939 | (currPolicy.priorityCategories &
2940 Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER);
2941 policy = new Policy(priorityCategories,
2942 policy.priorityCallSenders, policy.priorityMessageSenders,
2943 policy.suppressedVisualEffects);
2944 }
2945
John Spurlock1fc476d2015-04-14 16:05:20 -04002946 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05002947 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04002948 } finally {
2949 Binder.restoreCallingIdentity(identity);
2950 }
2951 }
Chris Wren51017d02015-12-15 15:34:46 -05002952
2953 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04002954 public List<String> getEnabledNotificationListenerPackages() {
2955 checkCallerIsSystem();
2956 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
2957 }
2958
2959 @Override
2960 public List<ComponentName> getEnabledNotificationListeners(int userId) {
2961 checkCallerIsSystem();
2962 return mListeners.getAllowedComponents(userId);
2963 }
2964
2965 @Override
2966 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
2967 Preconditions.checkNotNull(listener);
2968 checkCallerIsSystemOrSameApp(listener.getPackageName());
2969 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2970 getCallingUserHandle().getIdentifier());
2971 }
2972
2973 @Override
2974 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
2975 int userId) {
2976 Preconditions.checkNotNull(listener);
2977 checkCallerIsSystem();
2978 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2979 userId);
2980 }
2981
2982 @Override
2983 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
2984 Preconditions.checkNotNull(assistant);
2985 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002986 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04002987 getCallingUserHandle().getIdentifier());
2988 }
2989
2990 @Override
2991 public void setNotificationListenerAccessGranted(ComponentName listener,
2992 boolean granted) throws RemoteException {
2993 setNotificationListenerAccessGrantedForUser(
2994 listener, getCallingUserHandle().getIdentifier(), granted);
2995 }
2996
2997 @Override
2998 public void setNotificationAssistantAccessGranted(ComponentName assistant,
2999 boolean granted) throws RemoteException {
3000 setNotificationAssistantAccessGrantedForUser(
3001 assistant, getCallingUserHandle().getIdentifier(), granted);
3002 }
3003
3004 @Override
3005 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3006 boolean granted) throws RemoteException {
3007 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003008 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003009 final long identity = Binder.clearCallingIdentity();
3010 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04003011 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003012 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3013 userId, false, granted);
3014 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3015 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003016
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003017 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003018 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003019 .setPackage(listener.getPackageName())
3020 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003021 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003022
3023 savePolicyFile();
3024 }
3025 } finally {
3026 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003027 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003028 }
3029
3030 @Override
3031 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3032 int userId, boolean granted) throws RemoteException {
3033 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003034 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003035 final long identity = Binder.clearCallingIdentity();
3036 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04003037 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003038 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3039 userId, false, granted);
3040 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3041 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003042
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003043 getContext().sendBroadcastAsUser(new Intent(
3044 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3045 .setPackage(assistant.getPackageName())
3046 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003047 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003048
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003049 savePolicyFile();
3050 }
3051 } finally {
3052 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003053 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003054 }
3055
3056 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003057 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3058 Adjustment adjustment) throws RemoteException {
3059 final long identity = Binder.clearCallingIdentity();
3060 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003061 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003062 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003063 int N = mEnqueuedNotifications.size();
3064 for (int i = 0; i < N; i++) {
3065 final NotificationRecord n = mEnqueuedNotifications.get(i);
3066 if (Objects.equals(adjustment.getKey(), n.getKey())
3067 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3068 applyAdjustment(n, adjustment);
3069 break;
3070 }
3071 }
3072 }
3073 } finally {
3074 Binder.restoreCallingIdentity(identity);
3075 }
3076 }
3077
3078 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003079 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003080 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05003081 final long identity = Binder.clearCallingIdentity();
3082 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003083 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003084 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003085 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3086 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05003087 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003088 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04003089 } finally {
3090 Binder.restoreCallingIdentity(identity);
3091 }
3092 }
3093
3094 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003095 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003096 List<Adjustment> adjustments) throws RemoteException {
3097
3098 final long identity = Binder.clearCallingIdentity();
3099 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003100 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003101 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003102 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003103 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3104 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003105 }
3106 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003107 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05003108 } finally {
3109 Binder.restoreCallingIdentity(identity);
3110 }
3111 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003112
3113 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003114 public void updateNotificationChannelGroupFromPrivilegedListener(
3115 INotificationListener token, String pkg, UserHandle user,
3116 NotificationChannelGroup group) throws RemoteException {
3117 Preconditions.checkNotNull(user);
3118 verifyPrivilegedListener(token, user);
3119 createNotificationChannelGroup(
3120 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3121 savePolicyFile();
3122 }
3123
3124 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003125 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003126 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003127 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003128 Preconditions.checkNotNull(pkg);
3129 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003130
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003131 verifyPrivilegedListener(token, user);
3132 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003133 }
3134
3135 @Override
3136 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003137 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3138 Preconditions.checkNotNull(pkg);
3139 Preconditions.checkNotNull(user);
3140 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003141
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003142 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3143 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003144 }
3145
3146 @Override
3147 public ParceledListSlice<NotificationChannelGroup>
3148 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003149 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3150 Preconditions.checkNotNull(pkg);
3151 Preconditions.checkNotNull(user);
3152 verifyPrivilegedListener(token, user);
3153
3154 List<NotificationChannelGroup> groups = new ArrayList<>();
3155 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3156 pkg, getUidForPackageAndUser(pkg, user)));
3157 return new ParceledListSlice<>(groups);
3158 }
3159
3160 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003161 ManagedServiceInfo info;
3162 synchronized (mNotificationLock) {
3163 info = mListeners.checkServiceTokenLocked(token);
3164 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003165 if (!hasCompanionDevice(info)) {
3166 throw new SecurityException(info + " does not have access");
3167 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003168 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3169 throw new SecurityException(info + " does not have access");
3170 }
3171 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003172
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003173 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3174 int uid = 0;
3175 long identity = Binder.clearCallingIdentity();
3176 try {
3177 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3178 } finally {
3179 Binder.restoreCallingIdentity(identity);
3180 }
3181 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003182 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003183
3184 @Override
3185 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3186 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3187 throws RemoteException {
3188 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3189 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003190 };
John Spurlocka4294292014-03-24 18:02:32 -04003191
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003192 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3193 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003194 return;
3195 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003196 if (adjustment.getSignals() != null) {
3197 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003198 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003199 }
3200 }
3201
Julia Reynolds88860ce2017-06-01 16:55:49 -04003202 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003203 void addAutogroupKeyLocked(String key) {
3204 NotificationRecord r = mNotificationsByKey.get(key);
3205 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003206 return;
3207 }
Julia Reynolds51710712017-07-19 13:48:07 -04003208 if (r.sbn.getOverrideGroupKey() == null) {
3209 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3210 EventLogTags.writeNotificationAutogrouped(key);
3211 mRankingHandler.requestSort();
3212 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003213 }
3214
Julia Reynolds88860ce2017-06-01 16:55:49 -04003215 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003216 void removeAutogroupKeyLocked(String key) {
3217 NotificationRecord r = mNotificationsByKey.get(key);
3218 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003219 return;
3220 }
Julia Reynolds51710712017-07-19 13:48:07 -04003221 if (r.sbn.getOverrideGroupKey() != null) {
3222 addAutoGroupAdjustment(r, null);
3223 EventLogTags.writeNotificationUnautogrouped(key);
3224 mRankingHandler.requestSort();
3225 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003226 }
3227
3228 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3229 Bundle signals = new Bundle();
3230 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3231 Adjustment adjustment =
3232 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3233 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003234 }
3235
3236 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003237 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003238 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3239 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3240 if (summaries != null && summaries.containsKey(pkg)) {
3241 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003242 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003243 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003244 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003245 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003246 }
3247 }
3248 }
3249
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003250 @GuardedBy("mNotificationLock")
3251 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3252 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3253 return summaries != null && summaries.containsKey(sbn.getPackageName());
3254 }
3255
Julia Reynoldse46bb372016-03-17 11:05:58 -04003256 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003257 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3258 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003259 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003260 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3261 if (notificationRecord == null) {
3262 // The notification could have been cancelled again already. A successive
3263 // adjustment will post a summary if needed.
3264 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003265 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003266 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3267 userId = adjustedSbn.getUser().getIdentifier();
3268 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3269 if (summaries == null) {
3270 summaries = new ArrayMap<>();
3271 }
3272 mAutobundledSummaries.put(userId, summaries);
3273 if (!summaries.containsKey(pkg)) {
3274 // Add summary
3275 final ApplicationInfo appInfo =
3276 adjustedSbn.getNotification().extras.getParcelable(
3277 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3278 final Bundle extras = new Bundle();
3279 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003280 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003281 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003282 new Notification.Builder(getContext(), channelId)
3283 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003284 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003285 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003286 .setGroup(GroupHelper.AUTOGROUP_KEY)
3287 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3288 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3289 .setColor(adjustedSbn.getNotification().color)
3290 .setLocalOnly(true)
3291 .build();
3292 summaryNotification.extras.putAll(extras);
3293 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3294 if (appIntent != null) {
3295 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3296 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3297 }
3298 final StatusBarNotification summarySbn =
3299 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003300 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003301 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003302 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3303 adjustedSbn.getInitialPid(), summaryNotification,
3304 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3305 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003306 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003307 notificationRecord.getChannel());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003308 summaries.put(pkg, summarySbn.getKey());
3309 }
3310 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003311 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003312 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003313 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003314 }
3315 }
3316
John Spurlock32fe4c62014-10-02 12:16:02 -04003317 private String disableNotificationEffects(NotificationRecord record) {
3318 if (mDisableNotificationEffects) {
3319 return "booleanState";
3320 }
3321 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3322 return "listenerHints";
3323 }
3324 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3325 return "callState";
3326 }
3327 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003328 };
3329
Kweku Adams887f09c2017-11-13 17:12:20 -08003330 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003331 JSONObject dump = new JSONObject();
3332 try {
3333 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003334 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3335 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003336 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003337 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003338 } catch (JSONException e) {
3339 e.printStackTrace();
3340 }
3341 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003342 }
3343
Kweku Adams887f09c2017-11-13 17:12:20 -08003344 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003345 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3346 synchronized (mNotificationLock) {
3347 long records = proto.start(NotificationServiceDumpProto.RECORDS);
3348 int N = mNotificationList.size();
3349 if (N > 0) {
3350 for (int i = 0; i < N; i++) {
3351 final NotificationRecord nr = mNotificationList.get(i);
3352 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3353 nr.dump(proto, filter.redact);
Yi Jinc7f93072017-09-29 15:29:38 -07003354 proto.write(NotificationRecordProto.STATE, NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003355 }
3356 }
3357 N = mEnqueuedNotifications.size();
3358 if (N > 0) {
3359 for (int i = 0; i < N; i++) {
3360 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3361 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3362 nr.dump(proto, filter.redact);
Yi Jinc7f93072017-09-29 15:29:38 -07003363 proto.write(NotificationRecordProto.STATE, NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003364 }
3365 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003366 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3367 N = snoozed.size();
3368 if (N > 0) {
3369 for (int i = 0; i < N; i++) {
3370 final NotificationRecord nr = snoozed.get(i);
3371 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3372 nr.dump(proto, filter.redact);
Yi Jinc7f93072017-09-29 15:29:38 -07003373 proto.write(NotificationRecordProto.STATE, NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003374 }
3375 }
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003376 proto.end(records);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003377
Kweku Adams93304b62017-09-20 17:03:00 -07003378 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3379 mZenModeHelper.dump(proto);
3380 for (ComponentName suppressor : mEffectsSuppressors) {
3381 proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
3382 }
3383 proto.end(zenLog);
3384
3385 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3386 mListeners.dump(proto, filter);
3387 proto.end(listenersToken);
3388
3389 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3390
3391 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3392 long effectsToken = proto.start(
3393 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3394
3395 proto.write(
3396 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3397 final ArraySet<ManagedServiceInfo> listeners =
3398 mListenersDisablingEffects.valueAt(i);
3399 for (int j = 0; j < listeners.size(); j++) {
3400 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003401 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003402 }
3403
3404 proto.end(effectsToken);
3405 }
3406
3407 long assistantsToken = proto.start(
3408 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3409 mAssistants.dump(proto, filter);
3410 proto.end(assistantsToken);
3411
3412 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3413 mConditionProviders.dump(proto, filter);
3414 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003415
3416 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3417 mRankingHelper.dump(proto, filter);
3418 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003419 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003420
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003421 proto.flush();
3422 }
3423
Kweku Adams887f09c2017-11-13 17:12:20 -08003424 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003425 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003426 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003427 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003428 }
3429 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003430 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003431 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003432
John Spurlock50806fc2014-07-15 10:22:02 -04003433 if (!zenOnly) {
3434 synchronized (mToastQueue) {
3435 N = mToastQueue.size();
3436 if (N > 0) {
3437 pw.println(" Toast Queue:");
3438 for (int i=0; i<N; i++) {
3439 mToastQueue.get(i).dump(pw, " ", filter);
3440 }
3441 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003442 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003443 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003444 }
3445
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003446 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003447 if (!zenOnly) {
3448 N = mNotificationList.size();
John Spurlock25e2d242014-06-27 13:58:23 -04003449 if (N > 0) {
John Spurlock50806fc2014-07-15 10:22:02 -04003450 pw.println(" Notification List:");
John Spurlock25e2d242014-06-27 13:58:23 -04003451 for (int i=0; i<N; i++) {
John Spurlock50806fc2014-07-15 10:22:02 -04003452 final NotificationRecord nr = mNotificationList.get(i);
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003453 if (filter.filtered && !filter.matches(nr.sbn)) continue;
Dan Sandlera1770312015-07-10 13:59:29 -04003454 nr.dump(pw, " ", getContext(), filter.redact);
John Spurlock25e2d242014-06-27 13:58:23 -04003455 }
3456 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003457 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003458
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003459 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003460 N = mLights.size();
3461 if (N > 0) {
3462 pw.println(" Lights List:");
3463 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003464 if (i == N - 1) {
3465 pw.print(" > ");
3466 } else {
3467 pw.print(" ");
3468 }
3469 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003470 }
3471 pw.println(" ");
3472 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003473 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3474 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003475 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3476 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003477 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003478 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003479 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003480 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003481 }
3482 pw.println(" mArchive=" + mArchive.toString());
3483 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003484 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003485 while (iter.hasNext()) {
3486 final StatusBarNotification sbn = iter.next();
3487 if (filter != null && !filter.matches(sbn)) continue;
3488 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003489 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003490 if (iter.hasNext()) pw.println(" ...");
3491 break;
3492 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003493 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003494
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003495 if (!zenOnly) {
3496 N = mEnqueuedNotifications.size();
3497 if (N > 0) {
3498 pw.println(" Enqueued Notification List:");
3499 for (int i = 0; i < N; i++) {
3500 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3501 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3502 nr.dump(pw, " ", getContext(), filter.redact);
3503 }
3504 pw.println(" ");
3505 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003506
3507 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003508 }
3509 }
3510
John Spurlock50806fc2014-07-15 10:22:02 -04003511 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003512 pw.println("\n Ranking Config:");
3513 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003514
John Spurlock50806fc2014-07-15 10:22:02 -04003515 pw.println("\n Notification listeners:");
3516 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003517 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3518 pw.print(" mListenersDisablingEffects: (");
3519 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003520 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003521 final int hint = mListenersDisablingEffects.keyAt(i);
3522 if (i > 0) pw.print(';');
3523 pw.print("hint[" + hint + "]:");
3524
3525 final ArraySet<ManagedServiceInfo> listeners =
3526 mListenersDisablingEffects.valueAt(i);
3527 final int listenerSize = listeners.size();
3528
3529 for (int j = 0; j < listenerSize; j++) {
3530 if (i > 0) pw.print(',');
3531 final ManagedServiceInfo listener = listeners.valueAt(i);
3532 pw.print(listener.component);
3533 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003534 }
3535 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003536 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003537 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003538 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003539
Julia Reynolds520df6e2017-02-13 09:05:10 -05003540 if (!filter.filtered || zenOnly) {
3541 pw.println("\n Zen Mode:");
3542 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3543 mZenModeHelper.dump(pw, " ");
3544
3545 pw.println("\n Zen Log:");
3546 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003547 }
3548
John Spurlocke77bb362014-04-26 10:24:59 -04003549 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003550 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003551
3552 pw.println("\n Group summaries:");
3553 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3554 NotificationRecord r = entry.getValue();
3555 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3556 if (mNotificationsByKey.get(r.getKey()) != r) {
3557 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003558 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003559 }
3560 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003561
3562 if (!zenOnly) {
3563 pw.println("\n Usage Stats:");
3564 mUsageStats.dump(pw, " ", filter);
3565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566 }
3567 }
3568
Adam Lesinski182f73f2013-12-05 16:48:06 -08003569 /**
3570 * The private API only accessible to the system process.
3571 */
3572 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3573 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003574 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3575 channelId) {
3576 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3577 }
3578
3579 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003580 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003581 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003582 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003583 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003584 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003585
3586 @Override
3587 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3588 int userId) {
3589 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003590 mHandler.post(new Runnable() {
3591 @Override
3592 public void run() {
3593 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003594 removeForegroundServiceFlagByListLocked(
3595 mEnqueuedNotifications, pkg, notificationId, userId);
3596 removeForegroundServiceFlagByListLocked(
3597 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003598 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003599 }
3600 });
3601 }
3602
Julia Reynolds88860ce2017-06-01 16:55:49 -04003603 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003604 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003605 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3606 int userId) {
3607 NotificationRecord r = findNotificationByListLocked(
3608 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003609 if (r == null) {
3610 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003611 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003612 StatusBarNotification sbn = r.sbn;
3613 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3614 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3615 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3616 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3617 sbn.getNotification().flags =
3618 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3619 mRankingHelper.sort(mNotificationList);
3620 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
Christoph Studer365e4c32014-09-18 20:35:36 +02003621 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003622 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003624 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04003625 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003626 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04003627 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003628 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3629 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04003630 }
John Spurlock7340fc82014-04-24 18:50:12 -04003631 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003632
Scott Greenwald9b05c612013-06-25 23:44:05 -04003633 final int userId = ActivityManager.handleIncomingUser(callingPid,
3634 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07003635 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07003636
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003637 if (pkg == null || notification == null) {
3638 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3639 + " id=" + id + " notification=" + notification);
3640 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003641
3642 // The system can post notifications for any package, let us resolve that.
3643 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3644
Julia Reynoldse46bb372016-03-17 11:05:58 -04003645 // Fix the notification as best we can.
3646 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003647 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06003648 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3649 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04003650 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04003651
3652 int canColorize = mPackageManagerClient.checkPermission(
3653 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3654 if (canColorize == PERMISSION_GRANTED) {
3655 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3656 } else {
3657 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3658 }
3659
Julia Reynoldse46bb372016-03-17 11:05:58 -04003660 } catch (NameNotFoundException e) {
3661 Slog.e(TAG, "Cannot create a context for sending app", e);
3662 return;
3663 }
3664
Chris Wren888b7a82016-06-17 15:47:19 -04003665 mUsageStats.registerEnqueuedByApp(pkg);
3666
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003667 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04003668 String channelId = notification.getChannelId();
3669 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3670 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05003671 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003672 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003673 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003674 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003675 final String noChannelStr = "No Channel found for "
3676 + "pkg=" + pkg
3677 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04003678 + ", id=" + id
3679 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003680 + ", opPkg=" + opPkg
3681 + ", callingUid=" + callingUid
3682 + ", userId=" + userId
3683 + ", incomingUserId=" + incomingUserId
3684 + ", notificationUid=" + notificationUid
3685 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003686 Log.e(TAG, noChannelStr);
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003687 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
Geoffrey Pitschcadb5dc2017-04-11 11:35:02 -04003688 "Failed to post notification on channel \"" + channelId + "\"\n" +
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003689 "See log for more details");
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003690 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003691 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003692
Chris Wrena61f1792016-08-04 11:24:42 -04003693 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003694 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003695 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003696 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Chris Wrena61f1792016-08-04 11:24:42 -04003697
Julia Reynolds8617e4e2017-09-18 16:52:37 -04003698 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3699 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3700 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3701 // Increase the importance of foreground service notifications unless the user had an
3702 // opinion otherwise
3703 if (TextUtils.isEmpty(channelId)
3704 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3705 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3706 } else {
3707 channel.setImportance(IMPORTANCE_LOW);
3708 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3709 r.updateNotificationChannel(channel);
3710 }
3711 }
3712
Julia Reynolds5e702192017-08-18 09:22:40 -04003713 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3714 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003715 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07003716 }
3717
Felipe Lemedd85da62016-06-28 11:29:54 -07003718 // Whitelist pending intents.
3719 if (notification.allPendingIntents != null) {
3720 final int intentCount = notification.allPendingIntents.size();
3721 if (intentCount > 0) {
3722 final ActivityManagerInternal am = LocalServices
3723 .getService(ActivityManagerInternal.class);
3724 final long duration = LocalServices.getService(
3725 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3726 for (int i = 0; i < intentCount; i++) {
3727 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3728 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07003729 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3730 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07003731 }
3732 }
3733 }
3734 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07003735
Chris Wren47633422016-01-22 09:56:59 -05003736 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 }
3738
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003739 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003740 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003741 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003742 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3743 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003744 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04003745 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04003746 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003747 }
3748 }
3749
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003750 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3751 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003752 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003753 try {
3754 return getContext().getPackageManager()
3755 .getPackageUidAsUser(opPackageName, userId);
3756 } catch (NameNotFoundException e) {
3757 /* ignore */
3758 }
3759 }
3760 return callingUid;
3761 }
3762
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003763 /**
3764 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3765 *
3766 * Has side effects.
3767 */
3768 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04003769 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003770 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003771 final boolean isSystemNotification =
3772 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003773 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3774
3775 // Limit the number of notifications that any given package except the android
3776 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
3777 if (!isSystemNotification && !isNotificationFromListener) {
3778 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003779 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3780 // Ephemeral apps have some special constraints for notifications.
3781 // They are not allowed to create new notifications however they are allowed to
3782 // update notifications created by the system (e.g. a foreground service
3783 // notification).
3784 throw new SecurityException("Instant app " + pkg
3785 + " cannot create notifications");
3786 }
3787
3788 // rate limit updates that aren't completed progress notifications
3789 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04003790 && !r.getNotification().hasCompletedProgress()
3791 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003792
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003793 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3794 if (appEnqueueRate > mMaxPackageEnqueueRate) {
3795 mUsageStats.registerOverRateQuota(pkg);
3796 final long now = SystemClock.elapsedRealtime();
3797 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3798 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04003799 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003800 mLastOverRateLogTime = now;
3801 }
3802 return false;
3803 }
3804 }
3805
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003806 // limit the number of outstanding notificationrecords an app can have
3807 int count = getNotificationCountLocked(pkg, userId, id, tag);
3808 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3809 mUsageStats.registerOverCountQuota(pkg);
3810 Slog.e(TAG, "Package has already posted or enqueued " + count
3811 + " notifications. Not showing more. package=" + pkg);
3812 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003813 }
3814 }
3815 }
3816
3817 // snoozed apps
3818 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05003819 MetricsLogger.action(r.getLogMaker()
3820 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3821 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003822 if (DBG) {
3823 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3824 }
3825 mSnoozeHelper.update(userId, r);
3826 savePolicyFile();
3827 return false;
3828 }
3829
3830
3831 // blocked apps
3832 if (isBlocked(r, mUsageStats)) {
3833 return false;
3834 }
3835
3836 return true;
3837 }
3838
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003839 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3840 String excludedTag) {
3841 int count = 0;
3842 final int N = mNotificationList.size();
3843 for (int i = 0; i < N; i++) {
3844 final NotificationRecord existing = mNotificationList.get(i);
3845 if (existing.sbn.getPackageName().equals(pkg)
3846 && existing.sbn.getUserId() == userId) {
3847 if (existing.sbn.getId() == excludedId
3848 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3849 continue;
3850 }
3851 count++;
3852 }
3853 }
3854 final int M = mEnqueuedNotifications.size();
3855 for (int i = 0; i < M; i++) {
3856 final NotificationRecord existing = mEnqueuedNotifications.get(i);
3857 if (existing.sbn.getPackageName().equals(pkg)
3858 && existing.sbn.getUserId() == userId) {
3859 count++;
3860 }
3861 }
3862 return count;
3863 }
3864
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003865 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3866 final String pkg = r.sbn.getPackageName();
3867 final int callingUid = r.sbn.getUid();
3868
3869 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3870 if (isPackageSuspended) {
3871 Slog.e(TAG, "Suppressing notification from package due to package "
3872 + "suspended by administrator.");
3873 usageStats.registerSuspendedByAdmin(r);
3874 return isPackageSuspended;
3875 }
Julia Reynolds4da79702017-06-01 11:06:10 -04003876 final boolean isBlocked =
Julia Reynolds005c8b92017-08-24 10:35:53 -04003877 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
3878 || mRankingHelper.getImportance(pkg, callingUid)
3879 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04003880 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003881 if (isBlocked) {
3882 Slog.e(TAG, "Suppressing notification from package by user request.");
3883 usageStats.registerBlocked(r);
3884 }
3885 return isBlocked;
3886 }
3887
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003888 protected class SnoozeNotificationRunnable implements Runnable {
3889 private final String mKey;
3890 private final long mDuration;
3891 private final String mSnoozeCriterionId;
3892
3893 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3894 mKey = key;
3895 mDuration = duration;
3896 mSnoozeCriterionId = snoozeCriterionId;
3897 }
3898
3899 @Override
3900 public void run() {
3901 synchronized (mNotificationLock) {
3902 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3903 if (r != null) {
3904 snoozeLocked(r);
3905 }
3906 }
3907 }
3908
Julia Reynolds88860ce2017-06-01 16:55:49 -04003909 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003910 void snoozeLocked(NotificationRecord r) {
3911 if (r.sbn.isGroup()) {
3912 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3913 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3914 if (r.getNotification().isGroupSummary()) {
3915 // snooze summary and all children
3916 for (int i = 0; i < groupNotifications.size(); i++) {
3917 snoozeNotificationLocked(groupNotifications.get(i));
3918 }
3919 } else {
3920 // if there is a valid summary for this group, and we are snoozing the only
3921 // child, also snooze the summary
3922 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3923 if (groupNotifications.size() != 2) {
3924 snoozeNotificationLocked(r);
3925 } else {
3926 // snooze summary and the one child
3927 for (int i = 0; i < groupNotifications.size(); i++) {
3928 snoozeNotificationLocked(groupNotifications.get(i));
3929 }
3930 }
3931 } else {
3932 snoozeNotificationLocked(r);
3933 }
3934 }
3935 } else {
3936 // just snooze the one notification
3937 snoozeNotificationLocked(r);
3938 }
3939 }
3940
Julia Reynolds88860ce2017-06-01 16:55:49 -04003941 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003942 void snoozeNotificationLocked(NotificationRecord r) {
3943 MetricsLogger.action(r.getLogMaker()
3944 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3945 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04003946 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
3947 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003948 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3949 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04003950 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003951 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003952 updateLightsLocked();
3953 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003954 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003955 mSnoozeHelper.snooze(r);
3956 } else {
3957 mSnoozeHelper.snooze(r, mDuration);
3958 }
Julia Reynolds503ed942017-10-04 16:04:56 -04003959 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003960 savePolicyFile();
3961 }
3962 }
3963
Julia Reynoldsbaff4002016-12-15 11:34:26 -05003964 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05003965 private final NotificationRecord r;
3966 private final int userId;
3967
3968 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3969 this.userId = userId;
3970 this.r = r;
3971 };
3972
3973 @Override
3974 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003975 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05003976 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05003977 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05003978
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003979 final StatusBarNotification n = r.sbn;
3980 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3981 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3982 if (old != null) {
3983 // Retain ranking information from previous record
3984 r.copyRankingInformation(old);
3985 }
3986
3987 final int callingUid = n.getUid();
3988 final int callingPid = n.getInitialPid();
3989 final Notification notification = n.getNotification();
3990 final String pkg = n.getPackageName();
3991 final int id = n.getId();
3992 final String tag = n.getTag();
3993
3994 // Handle grouped notifications and bail out early if we
3995 // can to avoid extracting signals.
3996 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3997
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003998 // if this is a group child, unsnooze parent summary
3999 if (n.isGroup() && notification.isGroupChild()) {
4000 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4001 }
4002
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004003 // This conditional is a dirty hack to limit the logging done on
4004 // behalf of the download manager without affecting other apps.
4005 if (!pkg.equals("com.android.providers.downloads")
4006 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4007 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004008 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004009 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004010 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004011 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4012 pkg, id, tag, userId, notification.toString(),
4013 enqueueStatus);
4014 }
Chris Wren6676dab2016-12-21 18:26:27 -05004015
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004016 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004017
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004018 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004019 if (mAssistants.isEnabled()) {
4020 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004021 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004022 DELAY_FOR_ASSISTANT_TIME);
4023 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004024 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004025 }
4026 }
4027 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004028 }
4029
4030 protected class PostNotificationRunnable implements Runnable {
4031 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004032
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004033 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004034 this.key = key;
4035 }
4036
4037 @Override
4038 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004039 synchronized (mNotificationLock) {
4040 try {
4041 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004042 int N = mEnqueuedNotifications.size();
4043 for (int i = 0; i < N; i++) {
4044 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4045 if (Objects.equals(key, enqueued.getKey())) {
4046 r = enqueued;
4047 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004048 }
Chris Wren6676dab2016-12-21 18:26:27 -05004049 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004050 if (r == null) {
4051 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4052 return;
4053 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004054 NotificationRecord old = mNotificationsByKey.get(key);
4055 final StatusBarNotification n = r.sbn;
4056 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004057 int index = indexOfNotificationLocked(n.getKey());
4058 if (index < 0) {
4059 mNotificationList.add(r);
4060 mUsageStats.registerPostedByApp(r);
4061 } else {
4062 old = mNotificationList.get(index);
4063 mNotificationList.set(index, r);
4064 mUsageStats.registerUpdatedByApp(r, old);
4065 // Make sure we don't lose the foreground service state.
4066 notification.flags |=
4067 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
4068 r.isUpdate = true;
4069 }
4070
4071 mNotificationsByKey.put(n.getKey(), r);
4072
4073 // Ensure if this is a foreground service that the proper additional
4074 // flags are set.
4075 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4076 notification.flags |= Notification.FLAG_ONGOING_EVENT
4077 | Notification.FLAG_NO_CLEAR;
4078 }
4079
4080 applyZenModeLocked(r);
4081 mRankingHelper.sort(mNotificationList);
4082
4083 if (notification.getSmallIcon() != null) {
4084 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
4085 mListeners.notifyPostedLocked(n, oldSbn);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004086 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4087 mHandler.post(new Runnable() {
4088 @Override
4089 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004090 mGroupHelper.onNotificationPosted(
4091 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004092 }
4093 });
4094 }
Chris Wren6676dab2016-12-21 18:26:27 -05004095 } else {
4096 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4097 if (old != null && !old.isCanceled) {
4098 mListeners.notifyRemovedLocked(n,
Julia Reynolds503ed942017-10-04 16:04:56 -04004099 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004100 mHandler.post(new Runnable() {
4101 @Override
4102 public void run() {
4103 mGroupHelper.onNotificationRemoved(n);
4104 }
4105 });
4106 }
4107 // ATTENTION: in a future release we will bail out here
4108 // so that we do not play sounds, show lights, etc. for invalid
4109 // notifications
4110 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4111 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004112 }
Chris Wren47633422016-01-22 09:56:59 -05004113
Chris Wren6676dab2016-12-21 18:26:27 -05004114 buzzBeepBlinkLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004115 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004116 int N = mEnqueuedNotifications.size();
4117 for (int i = 0; i < N; i++) {
4118 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4119 if (Objects.equals(key, enqueued.getKey())) {
4120 mEnqueuedNotifications.remove(i);
4121 break;
4122 }
4123 }
Chris Wren6676dab2016-12-21 18:26:27 -05004124 }
Chris Wren47633422016-01-22 09:56:59 -05004125 }
4126 }
4127 }
4128
Christoph Studer265c1052014-07-23 17:14:33 +02004129 /**
4130 * Ensures that grouped notification receive their special treatment.
4131 *
4132 * <p>Cancels group children if the new notification causes a group to lose
4133 * its summary.</p>
4134 *
4135 * <p>Updates mSummaryByGroupKey.</p>
4136 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004137 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004138 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4139 int callingUid, int callingPid) {
4140 StatusBarNotification sbn = r.sbn;
4141 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004142 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4143 // notifications without a group shouldn't be a summary, otherwise autobundling can
4144 // lead to bugs
4145 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4146 }
4147
Christoph Studer265c1052014-07-23 17:14:33 +02004148 String group = sbn.getGroupKey();
4149 boolean isSummary = n.isGroupSummary();
4150
4151 Notification oldN = old != null ? old.sbn.getNotification() : null;
4152 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4153 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4154
4155 if (oldIsSummary) {
4156 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4157 if (removedSummary != old) {
4158 String removedKey =
4159 removedSummary != null ? removedSummary.getKey() : "<null>";
4160 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4161 ", removed=" + removedKey);
4162 }
4163 }
4164 if (isSummary) {
4165 mSummaryByGroupKey.put(group, r);
4166 }
4167
4168 // Clear out group children of the old notification if the update
4169 // causes the group summary to go away. This happens when the old
4170 // notification was a summary and the new one isn't, or when the old
4171 // notification was a summary and its group key changed.
4172 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004173 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4174 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004175 }
4176 }
4177
Chris Wren93bb8b82016-03-29 14:35:05 -04004178 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004179 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004180 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004181 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004182 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4183 REQUEST_CODE_TIMEOUT,
4184 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4185 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4186 .appendPath(record.getKey()).build())
4187 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4188 .putExtra(EXTRA_KEY, record.getKey()),
4189 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004190 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004191 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004192 }
4193 }
4194
4195 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004196 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004197 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004198 boolean buzz = false;
4199 boolean beep = false;
4200 boolean blink = false;
4201
Chris Wrena3446562014-06-03 18:11:47 -04004202 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004203 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004204
4205 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004206 final boolean aboveThreshold =
4207 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004208
4209 // Remember if this notification already owns the notification channels.
4210 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4211 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004212 // These are set inside the conditional if the notification is allowed to make noise.
4213 boolean hasValidVibrate = false;
4214 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004215 boolean sentAccessibilityEvent = false;
4216 // If the notification will appear in the status bar, it should send an accessibility
4217 // event
4218 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4219 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4220 sentAccessibilityEvent = true;
4221 }
Chris Wrena3446562014-06-03 18:11:47 -04004222
Julia Reynolds76c096d2017-06-19 08:16:04 -04004223 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004224
Julia Reynolds76c096d2017-06-19 08:16:04 -04004225 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004226 Uri soundUri = record.getSound();
4227 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4228 long[] vibration = record.getVibration();
4229 // Demote sound to vibration if vibration missing & phone in vibration mode.
4230 if (vibration == null
4231 && hasValidSound
4232 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004233 == AudioManager.RINGER_MODE_VIBRATE)
4234 && mAudioManager.getStreamVolume(
4235 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004236 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004237 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004238 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004239
Julia Reynolds76c096d2017-06-19 08:16:04 -04004240 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004241 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004242 if (!sentAccessibilityEvent) {
4243 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4244 sentAccessibilityEvent = true;
4245 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004246 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004247 if (hasValidSound) {
4248 mSoundNotificationKey = key;
4249 if (mInCall) {
4250 playInCallNotification();
4251 beep = true;
4252 } else {
4253 beep = playSound(record, soundUri);
4254 }
4255 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004256
Julia Reynolds7c96b582017-05-25 12:35:36 -04004257 final boolean ringerModeSilent =
4258 mAudioManager.getRingerModeInternal()
4259 == AudioManager.RINGER_MODE_SILENT;
4260 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4261 mVibrateNotificationKey = key;
4262
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004263 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04004264 }
Chris Wrena3446562014-06-03 18:11:47 -04004265 }
4266 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004267 }
4268 // If a notification is updated to remove the actively playing sound or vibrate,
4269 // cancel that feedback now
4270 if (wasBeep && !hasValidSound) {
4271 clearSoundLocked();
4272 }
4273 if (wasBuzz && !hasValidVibrate) {
4274 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004275 }
4276
4277 // light
4278 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004279 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004280 if (record.getLight() != null && aboveThreshold
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004281 && ((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05004282 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004283 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004284 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004285 if (mUseAttentionLight) {
4286 mAttentionLight.pulse();
4287 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004288 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004289 } else if (wasShowLights) {
4290 updateLightsLocked();
4291 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004292 if (buzz || beep || blink) {
Julia Reynolds445cfa82017-05-08 15:41:45 -04004293 MetricsLogger.action(record.getLogMaker()
4294 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4295 .setType(MetricsEvent.TYPE_OPEN)
4296 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4297 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004298 }
Chris Wrena3446562014-06-03 18:11:47 -04004299 }
4300
Julia Reynolds88860ce2017-06-01 16:55:49 -04004301 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004302 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004303 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004304 final Notification notification = record.getNotification();
4305 if(record.isUpdate
4306 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4307 return true;
4308 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004309
Julia Reynolds76c096d2017-06-19 08:16:04 -04004310 // muted by listener
4311 final String disableEffects = disableNotificationEffects(record);
4312 if (disableEffects != null) {
4313 ZenLog.traceDisableEffects(record, disableEffects);
4314 return true;
4315 }
4316
4317 // suppressed due to DND
4318 if (record.isIntercepted()) {
4319 return true;
4320 }
4321
4322 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004323 if (record.sbn.isGroup()) {
Julia Reynolds30203152017-05-26 13:36:31 -04004324 return notification.suppressAlertingDueToGrouping();
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004325 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004326
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004327 // Suppressed for being too recently noisy
4328 final String pkg = record.sbn.getPackageName();
4329 if (mUsageStats.isAlertRateLimited(pkg)) {
4330 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4331 return true;
4332 }
4333
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004334 return false;
4335 }
4336
Julia Reynolds0c299d42016-11-15 14:37:04 -05004337 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4338 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4339 // do not play notifications if there is a user of exclusive audio focus
Julia Reynolds2143e5d2017-01-17 16:28:48 -05004340 // or the device is in vibrate mode
Julia Reynolds85896572017-09-20 12:54:52 -04004341 if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
4342 != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
4343 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004344 final long identity = Binder.clearCallingIdentity();
4345 try {
4346 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4347 if (player != null) {
4348 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4349 + " with attributes " + record.getAudioAttributes());
4350 player.playAsync(soundUri, record.sbn.getUser(), looping,
4351 record.getAudioAttributes());
4352 return true;
4353 }
4354 } catch (RemoteException e) {
4355 } finally {
4356 Binder.restoreCallingIdentity(identity);
4357 }
4358 }
4359 return false;
4360 }
4361
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004362 private boolean playVibration(final NotificationRecord record, long[] vibration,
4363 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004364 // Escalate privileges so we can use the vibrator even if the
4365 // notifying app does not have the VIBRATE permission.
4366 long identity = Binder.clearCallingIdentity();
4367 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004368 final VibrationEffect effect;
4369 try {
4370 final boolean insistent =
4371 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4372 effect = VibrationEffect.createWaveform(
4373 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4374 } catch (IllegalArgumentException e) {
4375 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4376 Arrays.toString(vibration));
4377 return false;
4378 }
4379 if (delayVibForSound) {
4380 new Thread(() -> {
4381 // delay the vibration by the same amount as the notification sound
4382 final int waitMs = mAudioManager.getFocusRampTimeMs(
4383 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4384 record.getAudioAttributes());
4385 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4386 try {
4387 Thread.sleep(waitMs);
4388 } catch (InterruptedException e) { }
4389 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4390 effect, record.getAudioAttributes());
4391 }).start();
4392 } else {
4393 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4394 effect, record.getAudioAttributes());
4395 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004396 return true;
4397 } finally{
4398 Binder.restoreCallingIdentity(identity);
4399 }
4400 }
4401
Julia Reynolds7c96b582017-05-25 12:35:36 -04004402 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4403 final int currentUser;
4404 final long token = Binder.clearCallingIdentity();
4405 try {
4406 currentUser = ActivityManager.getCurrentUser();
4407 } finally {
4408 Binder.restoreCallingIdentity(token);
4409 }
4410 return (record.getUserId() == UserHandle.USER_ALL ||
4411 record.getUserId() == currentUser ||
4412 mUserProfiles.isCurrentProfile(record.getUserId()));
4413 }
4414
Beverly5d463b62017-07-26 14:13:40 -04004415 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01004416 new Thread() {
4417 @Override
4418 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04004419 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01004420 try {
Beverly5d463b62017-07-26 14:13:40 -04004421 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4422 if (player != null) {
4423 player.play(new Binder(), mInCallNotificationUri,
4424 mInCallNotificationAudioAttributes,
4425 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01004426 }
Beverly5d463b62017-07-26 14:13:40 -04004427 } catch (RemoteException e) {
4428 } finally {
4429 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01004430 }
4431 }
4432 }.start();
4433 }
4434
Julia Reynolds88860ce2017-06-01 16:55:49 -04004435 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004436 void showNextToastLocked() {
4437 ToastRecord record = mToastQueue.get(0);
4438 while (record != null) {
4439 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4440 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004441 record.callback.show(record.token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004442 scheduleTimeoutLocked(record);
4443 return;
4444 } catch (RemoteException e) {
4445 Slog.w(TAG, "Object died trying to show notification " + record.callback
4446 + " in package " + record.pkg);
4447 // remove it from the list and let the process die
4448 int index = mToastQueue.indexOf(record);
4449 if (index >= 0) {
4450 mToastQueue.remove(index);
4451 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004452 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004453 if (mToastQueue.size() > 0) {
4454 record = mToastQueue.get(0);
4455 } else {
4456 record = null;
4457 }
4458 }
4459 }
4460 }
4461
Julia Reynolds88860ce2017-06-01 16:55:49 -04004462 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004463 void cancelToastLocked(int index) {
4464 ToastRecord record = mToastQueue.get(index);
4465 try {
4466 record.callback.hide();
4467 } catch (RemoteException e) {
4468 Slog.w(TAG, "Object died trying to hide notification " + record.callback
4469 + " in package " + record.pkg);
4470 // don't worry about this, we're about to remove it from
4471 // the list anyway
4472 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004473
4474 ToastRecord lastToast = mToastQueue.remove(index);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07004475 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004476
4477 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004478 if (mToastQueue.size() > 0) {
4479 // Show the next one. If the callback fails, this will remove
4480 // it from the list, so don't assume that the list hasn't changed
4481 // after this point.
4482 showNextToastLocked();
4483 }
4484 }
4485
Julia Reynolds88860ce2017-06-01 16:55:49 -04004486 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004487 private void scheduleTimeoutLocked(ToastRecord r)
4488 {
4489 mHandler.removeCallbacksAndMessages(r);
4490 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4491 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4492 mHandler.sendMessageDelayed(m, delay);
4493 }
4494
4495 private void handleTimeout(ToastRecord record)
4496 {
4497 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4498 synchronized (mToastQueue) {
4499 int index = indexOfToastLocked(record.pkg, record.callback);
4500 if (index >= 0) {
4501 cancelToastLocked(index);
4502 }
4503 }
4504 }
4505
Julia Reynolds88860ce2017-06-01 16:55:49 -04004506 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004507 int indexOfToastLocked(String pkg, ITransientNotification callback)
4508 {
4509 IBinder cbak = callback.asBinder();
4510 ArrayList<ToastRecord> list = mToastQueue;
4511 int len = list.size();
4512 for (int i=0; i<len; i++) {
4513 ToastRecord r = list.get(i);
Beverly4ee785b2017-08-11 12:49:56 -04004514 if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4515 return i;
4516 }
4517 }
4518 return -1;
4519 }
4520
4521 @GuardedBy("mToastQueue")
4522 int indexOfToastPackageLocked(String pkg)
4523 {
4524 ArrayList<ToastRecord> list = mToastQueue;
4525 int len = list.size();
4526 for (int i=0; i<len; i++) {
4527 ToastRecord r = list.get(i);
4528 if (r.pkg.equals(pkg)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004529 return i;
4530 }
4531 }
4532 return -1;
4533 }
4534
Julia Reynolds88860ce2017-06-01 16:55:49 -04004535 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004536 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08004537 {
4538 int toastCount = 0; // toasts from this pid
4539 ArrayList<ToastRecord> list = mToastQueue;
4540 int N = list.size();
4541 for (int i=0; i<N; i++) {
4542 ToastRecord r = list.get(i);
4543 if (r.pid == pid) {
4544 toastCount++;
4545 }
4546 }
4547 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07004548 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08004549 } catch (RemoteException e) {
4550 // Shouldn't happen.
4551 }
4552 }
4553
Chris Wrenf9536642014-04-17 10:01:54 -04004554 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004555 if (!(message.obj instanceof RankingReconsideration)) return;
4556 RankingReconsideration recon = (RankingReconsideration) message.obj;
4557 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04004558 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004559 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004560 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4561 if (record == null) {
4562 return;
Chris Wrenf9536642014-04-17 10:01:54 -04004563 }
Chris Wren333a61c2014-05-28 16:40:57 -04004564 int indexBefore = findNotificationRecordIndexLocked(record);
4565 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004566 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004567 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04004568 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04004569 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04004570 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04004571 int indexAfter = findNotificationRecordIndexLocked(record);
4572 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004573 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004574 int visibilityAfter = record.getPackageVisibilityOverride();
4575 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4576 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004577 if (interceptBefore && !interceptAfter
4578 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04004579 buzzBeepBlinkLocked(record);
4580 }
Chris Wrenf9536642014-04-17 10:01:54 -04004581 }
Chris Wren333a61c2014-05-28 16:40:57 -04004582 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004583 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04004584 }
4585 }
4586
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004587 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04004588 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004589 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04004590 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004591 // Any field that can change via one of the extractors needs to be added here.
4592 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004593 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05004594 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004595 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4596 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4597 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4598 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04004599 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04004600 for (int i = 0; i < N; i++) {
4601 final NotificationRecord r = mNotificationList.get(i);
4602 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004603 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05004604 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004605 channelBefore.add(r.getChannel());
4606 groupKeyBefore.add(r.getGroupKey());
4607 overridePeopleBefore.add(r.getPeopleOverride());
4608 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04004609 userSentimentBefore.add(r.getUserSentiment());
Chris Wren54bbef42014-07-09 18:37:56 -04004610 mRankingHelper.extractSignals(r);
4611 }
Chris Wren19a02b02015-12-22 10:34:22 -05004612 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04004613 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004614 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004615 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05004616 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004617 || showBadges[i] != r.canShowBadge()
4618 || !Objects.equals(channelBefore.get(i), r.getChannel())
4619 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4620 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04004621 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
4622 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004623 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04004624 return;
4625 }
4626 }
4627 }
4628 }
4629
Julia Reynolds88860ce2017-06-01 16:55:49 -04004630 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004631 private void recordCallerLocked(NotificationRecord record) {
4632 if (mZenModeHelper.isCall(record)) {
4633 mZenModeHelper.recordCaller(record);
4634 }
4635 }
4636
Christoph Studerd5092bc2014-07-03 17:47:58 +02004637 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04004638 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04004639 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02004640 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004641 if (record.isIntercepted()) {
Julia Reynoldsd5607292016-02-05 15:25:58 -05004642 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4643 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4644 | (mZenModeHelper.shouldSuppressWhenScreenOn()
4645 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004646 record.setSuppressedVisualEffects(suppressed);
Julia Reynolds445cfa82017-05-08 15:41:45 -04004647 } else {
4648 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004649 }
Chris Wren333a61c2014-05-28 16:40:57 -04004650 }
4651
Julia Reynolds88860ce2017-06-01 16:55:49 -04004652 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04004653 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04004654 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04004655 }
4656
Chris Wrenf9536642014-04-17 10:01:54 -04004657 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004658 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04004659 mListeners.notifyRankingUpdateLocked();
Chris Wrenf9536642014-04-17 10:01:54 -04004660 }
4661 }
4662
John Spurlockd8afe3c2014-08-01 14:04:07 -04004663 private void scheduleListenerHintsChanged(int state) {
4664 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4665 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04004666 }
4667
Christoph Studer85a384b2014-08-27 20:16:15 +02004668 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4669 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4670 mHandler.obtainMessage(
4671 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4672 listenerInterruptionFilter,
4673 0).sendToTarget();
4674 }
4675
John Spurlockd8afe3c2014-08-01 14:04:07 -04004676 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004677 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004678 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004679 }
4680 }
4681
Christoph Studer85a384b2014-08-27 20:16:15 +02004682 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004683 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02004684 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4685 }
4686 }
4687
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004688 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08004689 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004690 public WorkerHandler(Looper looper) {
4691 super(looper);
4692 }
4693
Adam Lesinski182f73f2013-12-05 16:48:06 -08004694 @Override
4695 public void handleMessage(Message msg)
4696 {
4697 switch (msg.what)
4698 {
4699 case MESSAGE_TIMEOUT:
4700 handleTimeout((ToastRecord)msg.obj);
4701 break;
John Spurlock056c5192014-04-20 21:52:01 -04004702 case MESSAGE_SAVE_POLICY_FILE:
4703 handleSavePolicyFile();
4704 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004705 case MESSAGE_SEND_RANKING_UPDATE:
4706 handleSendRankingUpdate();
4707 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04004708 case MESSAGE_LISTENER_HINTS_CHANGED:
4709 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04004710 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02004711 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4712 handleListenerInterruptionFilterChanged(msg.arg1);
4713 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004714 }
4715 }
4716
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004717 protected void scheduleSendRankingUpdate() {
4718 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4719 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4720 sendMessage(m);
4721 }
4722 }
4723
Chris Wrenf9536642014-04-17 10:01:54 -04004724 }
4725
Chris Wren51017d02015-12-15 15:34:46 -05004726 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04004727 {
Chris Wren51017d02015-12-15 15:34:46 -05004728 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04004729 super(looper);
4730 }
4731
4732 @Override
4733 public void handleMessage(Message msg) {
4734 switch (msg.what) {
4735 case MESSAGE_RECONSIDER_RANKING:
4736 handleRankingReconsideration(msg);
4737 break;
Chris Wren51017d02015-12-15 15:34:46 -05004738 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004739 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04004740 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08004741 }
4742 }
Chris Wren51017d02015-12-15 15:34:46 -05004743
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004744 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05004745 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05004746 Message msg = Message.obtain();
4747 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05004748 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05004749 }
4750
4751 public void requestReconsideration(RankingReconsideration recon) {
4752 Message m = Message.obtain(this,
4753 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4754 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4755 sendMessageDelayed(m, delay);
4756 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004757 }
4758
Adam Lesinski182f73f2013-12-05 16:48:06 -08004759 // Notifications
4760 // ============================================================================
4761 static int clamp(int x, int low, int high) {
4762 return (x < low) ? low : ((x > high) ? high : x);
4763 }
4764
4765 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00004766 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07004767 return;
4768 }
4769
4770 AccessibilityEvent event =
4771 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4772 event.setPackageName(packageName);
4773 event.setClassName(Notification.class.getName());
4774 event.setParcelableData(notification);
4775 CharSequence tickerText = notification.tickerText;
4776 if (!TextUtils.isEmpty(tickerText)) {
4777 event.getText().add(tickerText);
4778 }
4779
Julia Reynolds94187562017-10-10 13:58:49 -04004780 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07004781 }
4782
Julia Reynolds0839c022017-06-15 15:24:01 -04004783 /**
4784 * Removes all NotificationsRecords with the same key as the given notification record
4785 * from both lists. Do not call this method while iterating over either list.
4786 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004787 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04004788 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4789 // Remove from both lists, either list could have a separate Record for what is
4790 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004791 boolean wasPosted = false;
4792 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04004793 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4794 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004795 mNotificationList.remove(recordInList);
4796 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004797 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004798 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004799 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004800 != null) {
4801 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004802 }
Julia Reynolds0839c022017-06-15 15:24:01 -04004803 return wasPosted;
4804 }
4805
4806 @GuardedBy("mNotificationLock")
4807 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04004808 boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04004809 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004810
4811 // Record caller.
4812 recordCallerLocked(r);
4813
Julia Reynolds503ed942017-10-04 16:04:56 -04004814 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
4815 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
4816 }
4817
Joe Onorato46439ce2010-11-19 13:56:21 -08004818 // tell the app
4819 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004820 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08004821 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004822 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08004823 } catch (PendingIntent.CanceledException ex) {
4824 // do nothing - there's no relevant way to recover, and
4825 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04004826 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08004827 }
4828 }
4829 }
4830
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004831 // Only cancel these if this notification actually got to be posted.
4832 if (wasPosted) {
4833 // status bar
4834 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004835 if (reason != REASON_SNOOZED) {
4836 r.isCanceled = true;
4837 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004838 mListeners.notifyRemovedLocked(r.sbn, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004839 mHandler.post(new Runnable() {
4840 @Override
4841 public void run() {
4842 mGroupHelper.onNotificationRemoved(r.sbn);
4843 }
4844 });
4845 }
4846
4847 // sound
4848 if (canceledKey.equals(mSoundNotificationKey)) {
4849 mSoundNotificationKey = null;
4850 final long identity = Binder.clearCallingIdentity();
4851 try {
4852 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4853 if (player != null) {
4854 player.stopAsync();
4855 }
4856 } catch (RemoteException e) {
4857 } finally {
4858 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004859 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004861
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004862 // vibrate
4863 if (canceledKey.equals(mVibrateNotificationKey)) {
4864 mVibrateNotificationKey = null;
4865 long identity = Binder.clearCallingIdentity();
4866 try {
4867 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07004868 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004869 finally {
4870 Binder.restoreCallingIdentity(identity);
4871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004872 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004873
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004874 // light
4875 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004876 }
4877
Christoph Studer546bec82014-03-14 12:17:12 +01004878 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04004879 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01004880 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04004881 case REASON_CANCEL:
4882 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01004883 case REASON_LISTENER_CANCEL:
4884 case REASON_LISTENER_CANCEL_ALL:
4885 mUsageStats.registerDismissedByUser(r);
4886 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05004887 case REASON_APP_CANCEL:
4888 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01004889 mUsageStats.registerRemovedByApp(r);
4890 break;
Christoph Studer546bec82014-03-14 12:17:12 +01004891 }
4892
Christoph Studer265c1052014-07-23 17:14:33 +02004893 String groupKey = r.getGroupKey();
4894 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004895 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02004896 mSummaryByGroupKey.remove(groupKey);
4897 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04004898 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4899 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4900 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04004901 }
Christoph Studercef37cf2014-07-25 14:18:17 +02004902
Daniel Sandler23d7c702013-03-07 16:32:06 -05004903 // Save it for users of getHistoricalNotifications()
4904 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02004905
Chris Wren6650e572015-05-15 17:19:25 -04004906 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -05004907 MetricsLogger.action(r.getLogMaker(now)
4908 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4909 .setType(MetricsEvent.TYPE_DISMISS)
4910 .setSubtype(reason));
Chris Wrene6ddb8a2015-05-27 15:21:00 -04004911 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04004912 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004913 }
4914
4915 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07004916 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004917 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004918 */
John Spurlocke6a7d932014-03-13 12:29:00 -04004919 void cancelNotification(final int callingUid, final int callingPid,
4920 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004921 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04004922 final int userId, final int reason, final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004923 // In enqueueNotificationInternal notifications are added by scheduling the
4924 // work on the worker handler. Hence, we also schedule the cancel on this
4925 // handler to avoid a scenario where an add notification call followed by a
4926 // remove notification call ends up in not removing the notification.
4927 mHandler.post(new Runnable() {
4928 @Override
4929 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02004930 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08004931 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4932 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004933
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004934 synchronized (mNotificationLock) {
4935 // Look for the notification, searching both the posted and enqueued lists.
4936 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4937 if (r != null) {
4938 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004939
Christoph Studer546bec82014-03-14 12:17:12 +01004940 // Ideally we'd do this in the caller of this method. However, that would
4941 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04004942 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01004943 mUsageStats.registerClickedByUser(r);
4944 }
4945
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004946 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4947 return;
4948 }
4949 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4950 return;
4951 }
4952
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004953 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04004954 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004955 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02004956 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04004957 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004958 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004959 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004960 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004961 if (reason != REASON_SNOOZED) {
4962 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4963 if (wasSnoozed) {
4964 savePolicyFile();
4965 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004966 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004967 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004969 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004970 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004971 }
4972
4973 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07004974 * Determine whether the userId applies to the notification in question, either because
4975 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4976 */
4977 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4978 return
4979 // looking for USER_ALL notifications? match everything
4980 userId == UserHandle.USER_ALL
4981 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004982 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07004983 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004984 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07004985 }
4986
4987 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004988 * Determine whether the userId applies to the notification in question, either because
4989 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01004990 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004991 */
Kenny Guy2a764942014-04-02 13:29:20 +01004992 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00004993 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04004994 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004995 }
4996
4997 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05004998 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004999 * {@code mustHaveFlags}.
5000 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005001 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005002 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005003 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005004 mHandler.post(new Runnable() {
5005 @Override
5006 public void run() {
5007 String listenerName = listener == null ? null : listener.component.toShortString();
5008 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5009 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5010 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005011
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005012 // Why does this parameter exist? Do we actually want to execute the above if doit
5013 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005014 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005015 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005016 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005017
5018 synchronized (mNotificationLock) {
5019 FlagChecker flagChecker = (int flags) -> {
5020 if ((flags & mustHaveFlags) != mustHaveFlags) {
5021 return false;
5022 }
5023 if ((flags & mustNotHaveFlags) != 0) {
5024 return false;
5025 }
5026 return true;
5027 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005028 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5029 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5030 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005031 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005032 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5033 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5034 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005035 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005036 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005037 }
5038 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005039 });
5040 }
5041
5042 private interface FlagChecker {
5043 // Returns false if these flags do not pass the defined flag test.
5044 public boolean apply(int flags);
5045 }
5046
Julia Reynolds88860ce2017-06-01 16:55:49 -04005047 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005048 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5049 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5050 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005051 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005052 ArrayList<NotificationRecord> canceledNotifications = null;
5053 for (int i = notificationList.size() - 1; i >= 0; --i) {
5054 NotificationRecord r = notificationList.get(i);
5055 if (includeCurrentProfiles) {
5056 if (!notificationMatchesCurrentProfiles(r, userId)) {
5057 continue;
5058 }
5059 } else if (!notificationMatchesUserId(r, userId)) {
5060 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005061 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005062 // Don't remove notifications to all, if there's no package name specified
5063 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5064 continue;
5065 }
5066 if (!flagChecker.apply(r.getFlags())) {
5067 continue;
5068 }
5069 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5070 continue;
5071 }
5072 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5073 continue;
5074 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005075 if (canceledNotifications == null) {
5076 canceledNotifications = new ArrayList<>();
5077 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005078 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005079 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005080 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005081 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005082 }
5083 if (canceledNotifications != null) {
5084 final int M = canceledNotifications.size();
5085 for (int i = 0; i < M; i++) {
5086 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005087 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005088 }
5089 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005090 }
5091 }
5092
Julia Reynolds50989772017-02-23 14:32:16 -05005093 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005094 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005095 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005096 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005097 return;
5098 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005099
Julia Reynolds79672302017-01-12 08:30:16 -05005100 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005101 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5102 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005103 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005104 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005105 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005106 }
5107
5108 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5109 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005110 if (DBG) {
5111 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5112 }
Julia Reynolds79672302017-01-12 08:30:16 -05005113 mSnoozeHelper.repost(key);
5114 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005115 }
5116
Julia Reynolds88860ce2017-06-01 16:55:49 -04005117 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005118 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005119 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005120 mHandler.post(new Runnable() {
5121 @Override
5122 public void run() {
5123 synchronized (mNotificationLock) {
5124 String listenerName =
5125 listener == null ? null : listener.component.toShortString();
5126 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5127 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005128
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005129 FlagChecker flagChecker = (int flags) -> {
5130 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5131 != 0) {
5132 return false;
5133 }
5134 return true;
5135 };
5136
5137 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5138 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5139 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005140 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005141 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5142 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5143 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005144 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005145 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005146 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005147 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005148 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005149 }
5150
Christoph Studere4ef156b2014-07-04 18:41:57 +02005151 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005152 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005153 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005154 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005155 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005156 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005157 return;
5158 }
5159
5160 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005161
5162 if (pkg == null) {
5163 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5164 return;
5165 }
5166
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005167 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005168 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005169 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005170 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005171 }
5172
Julia Reynolds88860ce2017-06-01 16:55:49 -04005173 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005174 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5175 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005176 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005177 final String pkg = parentNotification.sbn.getPackageName();
5178 final int userId = parentNotification.getUserId();
5179 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5180 for (int i = notificationList.size() - 1; i >= 0; i--) {
5181 final NotificationRecord childR = notificationList.get(i);
5182 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005183 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005184 childR.getGroupKey().equals(parentNotification.getGroupKey())
Beverly40239d92017-07-07 10:20:41 -04005185 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5186 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02005187 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5188 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04005189 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005190 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04005191 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005192 }
5193 }
5194 }
5195
Julia Reynolds88860ce2017-06-01 16:55:49 -04005196 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005197 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005198 {
The Android Open Source Project10592532009-03-18 17:39:46 -07005199 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05005200 NotificationRecord ledNotification = null;
5201 while (ledNotification == null && !mLights.isEmpty()) {
5202 final String owner = mLights.get(mLights.size() - 1);
5203 ledNotification = mNotificationsByKey.get(owner);
5204 if (ledNotification == null) {
5205 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5206 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005207 }
5208 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005209
Mike Lockwood63b5ad92011-08-30 09:55:30 -04005210 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05005211 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05005212 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07005213 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005214 NotificationRecord.Light light = ledNotification.getLight();
5215 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05005216 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005217 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5218 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05005219 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005221 }
5222
Julia Reynolds88860ce2017-06-01 16:55:49 -04005223 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005224 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5225 String groupKey, int userId) {
5226 List<NotificationRecord> records = new ArrayList<>();
5227 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5228 records.addAll(
5229 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5230 return records;
5231 }
5232
5233
Julia Reynolds88860ce2017-06-01 16:55:49 -04005234 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005235 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5236 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5237 List<NotificationRecord> records = new ArrayList<>();
5238 final int len = list.size();
5239 for (int i = 0; i < len; i++) {
5240 NotificationRecord r = list.get(i);
5241 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5242 && r.sbn.getPackageName().equals(pkg)) {
5243 records.add(r);
5244 }
5245 }
5246 return records;
5247 }
5248
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005249 // Searches both enqueued and posted notifications by key.
5250 // TODO: need to combine a bunch of these getters with slightly different behavior.
5251 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04005252 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005253 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005254 NotificationRecord r;
5255 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5256 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005257 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005258 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5259 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005260 }
5261 return null;
5262 }
5263
Julia Reynolds88860ce2017-06-01 16:55:49 -04005264 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005265 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005266 NotificationRecord r;
5267 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5268 return r;
5269 }
5270 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5271 != null) {
5272 return r;
5273 }
5274 return null;
5275 }
5276
Julia Reynolds88860ce2017-06-01 16:55:49 -04005277 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005278 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005279 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005280 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005281 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005282 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01005283 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5284 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005285 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005286 }
5287 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005288 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005289 }
5290
Julia Reynolds88860ce2017-06-01 16:55:49 -04005291 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005292 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04005293 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005294 final int N = list.size();
5295 for (int i = 0; i < N; i++) {
5296 if (key.equals(list.get(i).getKey())) {
5297 return list.get(i);
5298 }
5299 }
5300 return null;
5301 }
5302
Julia Reynolds88860ce2017-06-01 16:55:49 -04005303 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02005304 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02005305 final int N = mNotificationList.size();
5306 for (int i = 0; i < N; i++) {
5307 if (key.equals(mNotificationList.get(i).getKey())) {
5308 return i;
5309 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02005310 }
Christoph Studerc5115552014-06-12 20:22:31 +02005311 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02005312 }
5313
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005314 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005315 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005316 updateLightsLocked();
5317 }
5318 }
John Spurlocke677d712014-02-13 12:52:19 -05005319
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005320 protected boolean isCallingUidSystem() {
5321 final int uid = Binder.getCallingUid();
5322 return uid == Process.SYSTEM_UID;
5323 }
5324
5325 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04005326 final int appid = UserHandle.getAppId(uid);
5327 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5328 }
John Spurlockb408e8e2014-04-23 21:12:45 -04005329
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005330 // TODO: Most calls should probably move to isCallerSystem.
5331 protected boolean isCallerSystemOrPhone() {
5332 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04005333 }
5334
Julia Reynoldsb852e562017-06-06 16:14:18 -04005335 private void checkCallerIsSystemOrShell() {
5336 if (Binder.getCallingUid() == Process.SHELL_UID) {
5337 return;
5338 }
5339 checkCallerIsSystem();
5340 }
5341
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005342 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005343 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005344 return;
5345 }
5346 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5347 }
5348
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005349 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005350 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005351 return;
5352 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04005353 checkCallerIsSameApp(pkg);
5354 }
5355
Chad Brubaker6b68f102017-01-27 13:39:00 -08005356 private boolean isCallerInstantApp(String pkg) {
5357 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005358 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08005359 return false;
5360 }
5361
5362 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5363
5364 try {
5365 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5366 UserHandle.getCallingUserId());
5367 if (ai == null) {
5368 throw new SecurityException("Unknown package " + pkg);
5369 }
5370 return ai.isInstantApp();
5371 } catch (RemoteException re) {
5372 throw new SecurityException("Unknown package " + pkg, re);
5373 }
5374
5375 }
5376
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005377 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04005378 final int uid = Binder.getCallingUid();
5379 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005380 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04005381 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04005382 if (ai == null) {
5383 throw new SecurityException("Unknown package " + pkg);
5384 }
John Spurlock7340fc82014-04-24 18:50:12 -04005385 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005386 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04005387 + pkg + " which is owned by uid " + ai.uid);
5388 }
5389 } catch (RemoteException re) {
5390 throw new SecurityException("Unknown package " + pkg + "\n" + re);
5391 }
5392 }
5393
John Spurlock32fe4c62014-10-02 12:16:02 -04005394 private static String callStateToString(int state) {
5395 switch (state) {
5396 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5397 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5398 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5399 default: return "CALL_STATE_UNKNOWN_" + state;
5400 }
5401 }
5402
5403 private void listenForCallState() {
5404 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5405 @Override
5406 public void onCallStateChanged(int state, String incomingNumber) {
5407 if (mCallState == state) return;
5408 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5409 mCallState = state;
5410 }
5411 }, PhoneStateListener.LISTEN_CALL_STATE);
5412 }
5413
Christoph Studer05ad4822014-05-16 14:16:03 +02005414 /**
5415 * Generates a NotificationRankingUpdate from 'sbns', considering only
5416 * notifications visible to the given listener.
5417 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005418 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005419 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04005420 final int N = mNotificationList.size();
5421 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02005422 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05005423 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04005424 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005425 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005426 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05005427 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005428 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05005429 Bundle overridePeople = new Bundle();
5430 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005431 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04005432 Bundle userSentiment = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04005433 for (int i = 0; i < N; i++) {
5434 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02005435 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005436 continue;
5437 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005438 final String key = record.sbn.getKey();
5439 keys.add(key);
5440 importance.add(record.getImportance());
5441 if (record.getImportanceExplanation() != null) {
5442 explanation.putCharSequence(key, record.getImportanceExplanation());
5443 }
Chris Wren333a61c2014-05-28 16:40:57 -04005444 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005445 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005446
Christoph Studer05ad4822014-05-16 14:16:03 +02005447 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005448 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005449 if (record.getPackageVisibilityOverride()
5450 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005451 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005452 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04005453 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05005454 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05005455 overridePeople.putStringArrayList(key, record.getPeopleOverride());
5456 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05005457 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04005458 userSentiment.putInt(key, record.getUserSentiment());
Christoph Studer05ad4822014-05-16 14:16:03 +02005459 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005460 final int M = keys.size();
5461 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02005462 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05005463 int[] importanceAr = new int[M];
5464 for (int i = 0; i < M; i++) {
5465 importanceAr[i] = importance.get(i);
5466 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005467 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05005468 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Julia Reynolds503ed942017-10-04 16:04:56 -04005469 channels, overridePeople, snoozeCriteria, showBadge, userSentiment);
Christoph Studer05ad4822014-05-16 14:16:03 +02005470 }
5471
Julia Reynoldsda781472017-04-12 09:41:16 -04005472 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005473 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04005474 mCompanionManager = getCompanionManager();
5475 }
5476 // Companion mgr doesn't exist on all device types
5477 if (mCompanionManager == null) {
5478 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005479 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005480 long identity = Binder.clearCallingIdentity();
5481 try {
5482 List<String> associations = mCompanionManager.getAssociations(
5483 info.component.getPackageName(), info.userid);
5484 if (!ArrayUtils.isEmpty(associations)) {
5485 return true;
5486 }
5487 } catch (SecurityException se) {
5488 // Not a privileged listener
5489 } catch (RemoteException re) {
5490 Slog.e(TAG, "Cannot reach companion device service", re);
5491 } catch (Exception e) {
5492 Slog.e(TAG, "Cannot verify listener " + info, e);
5493 } finally {
5494 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005495 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005496 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005497 }
5498
Julia Reynolds727a7282017-04-13 10:54:01 -04005499 protected ICompanionDeviceManager getCompanionManager() {
5500 return ICompanionDeviceManager.Stub.asInterface(
5501 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5502 }
5503
Christoph Studercef37cf2014-07-25 14:18:17 +02005504 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5505 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5506 return false;
5507 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07005508 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02005509 return true;
5510 }
5511
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00005512 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005513 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005514 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005515 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005516 } catch (RemoteException re) {
5517 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00005518 } catch (IllegalArgumentException ex) {
5519 // Package not found.
5520 return false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005521 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005522 }
5523
Julia Reynoldse1816412017-10-24 10:39:11 -04005524 private boolean canUseManagedServices() {
5525 return !mActivityManager.isLowRamDevice()
5526 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
5527 }
5528
Chris Wren47633422016-01-22 09:56:59 -05005529 private class TrimCache {
5530 StatusBarNotification heavy;
5531 StatusBarNotification sbnClone;
5532 StatusBarNotification sbnCloneLight;
5533
5534 TrimCache(StatusBarNotification sbn) {
5535 heavy = sbn;
5536 }
5537
5538 StatusBarNotification ForListener(ManagedServiceInfo info) {
5539 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5540 if (sbnCloneLight == null) {
5541 sbnCloneLight = heavy.cloneLight();
5542 }
5543 return sbnCloneLight;
5544 } else {
5545 if (sbnClone == null) {
5546 sbnClone = heavy.clone();
5547 }
5548 return sbnClone;
5549 }
5550 }
5551 }
5552
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005553 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005554 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05005555
Julia Reynoldsb852e562017-06-06 16:14:18 -04005556 public NotificationAssistants(IPackageManager pm) {
5557 super(getContext(), mNotificationLock, mUserProfiles, pm);
Chris Wren51017d02015-12-15 15:34:46 -05005558 }
5559
5560 @Override
5561 protected Config getConfig() {
5562 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04005563 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005564 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005565 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005566 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5567 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05005568 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005569 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05005570 return c;
5571 }
5572
5573 @Override
5574 protected IInterface asInterface(IBinder binder) {
5575 return INotificationListener.Stub.asInterface(binder);
5576 }
5577
5578 @Override
5579 protected boolean checkType(IInterface service) {
5580 return service instanceof INotificationListener;
5581 }
5582
5583 @Override
5584 protected void onServiceAdded(ManagedServiceInfo info) {
5585 mListeners.registerGuestService(info);
5586 }
5587
5588 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005589 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05005590 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5591 mListeners.unregisterService(removed.service, removed.userid);
5592 }
Chris Wren47633422016-01-22 09:56:59 -05005593
5594 public void onNotificationEnqueued(final NotificationRecord r) {
5595 final StatusBarNotification sbn = r.sbn;
5596 TrimCache trimCache = new TrimCache(sbn);
5597
Chris Wren47633422016-01-22 09:56:59 -05005598 // There should be only one, but it's a list, so while we enforce
5599 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04005600 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05005601 boolean sbnVisible = isVisibleToListener(sbn, info);
5602 if (!sbnVisible) {
5603 continue;
5604 }
5605
Chris Wren47633422016-01-22 09:56:59 -05005606 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005607 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05005608 @Override
5609 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005610 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05005611 }
5612 });
5613 }
5614 }
5615
5616 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005617 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005618 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05005619 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5620 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005621 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05005622 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005623 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05005624 }
5625 }
5626
Julia Reynolds79672302017-01-12 08:30:16 -05005627 /**
5628 * asynchronously notify the assistant that a notification has been snoozed until a
5629 * context
5630 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005631 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05005632 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5633 final String snoozeCriterionId) {
5634 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04005635 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04005636 boolean sbnVisible = isVisibleToListener(sbn, info);
5637 if (!sbnVisible) {
5638 continue;
5639 }
Julia Reynolds79672302017-01-12 08:30:16 -05005640 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5641 mHandler.post(new Runnable() {
5642 @Override
5643 public void run() {
5644 final INotificationListener assistant =
5645 (INotificationListener) info.service;
5646 StatusBarNotificationHolder sbnHolder
5647 = new StatusBarNotificationHolder(sbnToPost);
5648 try {
5649 assistant.onNotificationSnoozedUntilContext(
5650 sbnHolder, snoozeCriterionId);
5651 } catch (RemoteException ex) {
5652 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5653 }
5654 }
5655 });
5656 }
5657 }
5658
Chris Wren47633422016-01-22 09:56:59 -05005659 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04005660 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05005661 }
Chris Wren51017d02015-12-15 15:34:46 -05005662 }
5663
John Spurlock7340fc82014-04-24 18:50:12 -04005664 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005665 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04005666
Christoph Studerb82bc782014-08-20 14:29:43 +02005667 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5668
Julia Reynoldsb852e562017-06-06 16:14:18 -04005669 public NotificationListeners(IPackageManager pm) {
5670 super(getContext(), mNotificationLock, mUserProfiles, pm);
5671
John Spurlock7340fc82014-04-24 18:50:12 -04005672 }
5673
5674 @Override
5675 protected Config getConfig() {
5676 Config c = new Config();
5677 c.caption = "notification listener";
5678 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005679 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04005680 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5681 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5682 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5683 c.clientLabel = R.string.notification_listener_binding_label;
5684 return c;
5685 }
5686
5687 @Override
5688 protected IInterface asInterface(IBinder binder) {
5689 return INotificationListener.Stub.asInterface(binder);
5690 }
5691
5692 @Override
Chris Wren51017d02015-12-15 15:34:46 -05005693 protected boolean checkType(IInterface service) {
5694 return service instanceof INotificationListener;
5695 }
5696
5697 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04005698 public void onServiceAdded(ManagedServiceInfo info) {
5699 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04005700 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005701 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04005702 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005703 }
John Spurlock7340fc82014-04-24 18:50:12 -04005704 try {
Chris Wren333a61c2014-05-28 16:40:57 -04005705 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04005706 } catch (RemoteException e) {
5707 // we tried
5708 }
5709 }
5710
John Spurlock1fa865f2014-07-21 14:56:39 -04005711 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005712 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04005713 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07005714 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005715 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01005716 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04005717 }
Christoph Studerb82bc782014-08-20 14:29:43 +02005718 mLightTrimListeners.remove(removed);
5719 }
5720
Julia Reynolds88860ce2017-06-01 16:55:49 -04005721 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02005722 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5723 if (trim == TRIM_LIGHT) {
5724 mLightTrimListeners.add(info);
5725 } else {
5726 mLightTrimListeners.remove(info);
5727 }
5728 }
5729
5730 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5731 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04005732 }
5733
John Spurlock7340fc82014-04-24 18:50:12 -04005734 /**
5735 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02005736 *
5737 * <p>
5738 * Also takes care of removing a notification that has been visible to a listener before,
5739 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04005740 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005741 @GuardedBy("mNotificationLock")
Christoph Studercef37cf2014-07-25 14:18:17 +02005742 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
Christoph Studerb82bc782014-08-20 14:29:43 +02005743 // Lazily initialized snapshots of the notification.
Chris Wren47633422016-01-22 09:56:59 -05005744 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02005745
Julia Reynolds00314d92017-04-14 10:01:24 -04005746 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005747 boolean sbnVisible = isVisibleToListener(sbn, info);
5748 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5749 // This notification hasn't been and still isn't visible -> ignore.
5750 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005751 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005752 }
Chris Wren333a61c2014-05-28 16:40:57 -04005753 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02005754
5755 // This notification became invisible -> remove the old one.
5756 if (oldSbnVisible && !sbnVisible) {
5757 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5758 mHandler.post(new Runnable() {
5759 @Override
5760 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04005761 notifyRemoved(
5762 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02005763 }
5764 });
Christoph Studer05ad4822014-05-16 14:16:03 +02005765 continue;
5766 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005767
Chris Wren47633422016-01-22 09:56:59 -05005768 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005769 mHandler.post(new Runnable() {
5770 @Override
5771 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02005772 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02005773 }
5774 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005775 }
5776 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005777
John Spurlock7340fc82014-04-24 18:50:12 -04005778 /**
5779 * asynchronously notify all listeners about a removed notification
5780 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005781 @GuardedBy("mNotificationLock")
Julia Reynolds503ed942017-10-04 16:04:56 -04005782 public void notifyRemovedLocked(StatusBarNotification sbn, int reason,
5783 NotificationStats notificationStats) {
John Spurlock7340fc82014-04-24 18:50:12 -04005784 // make a copy in case changes are made to the underlying Notification object
5785 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5786 // notification
5787 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04005788 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005789 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005790 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005791 }
Julia Reynolds503ed942017-10-04 16:04:56 -04005792 // Only assistants can get stats
5793 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
5794 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04005795 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005796 mHandler.post(new Runnable() {
5797 @Override
5798 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04005799 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02005800 }
5801 });
Chris Wrenf9536642014-04-17 10:01:54 -04005802 }
5803 }
5804
5805 /**
5806 * asynchronously notify all listeners about a reordering of notifications
Chris Wrenf9536642014-04-17 10:01:54 -04005807 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005808 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005809 public void notifyRankingUpdateLocked() {
Julia Reynolds00314d92017-04-14 10:01:24 -04005810 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005811 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5812 continue;
5813 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005814 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
John Spurlock7340fc82014-04-24 18:50:12 -04005815 mHandler.post(new Runnable() {
5816 @Override
5817 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -04005818 notifyRankingUpdate(serviceInfo, update);
John Spurlock7340fc82014-04-24 18:50:12 -04005819 }
5820 });
Kenny Guya263e4e2014-03-03 18:24:03 +00005821 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005822 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005823
Julia Reynolds88860ce2017-06-01 16:55:49 -04005824 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04005825 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005826 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04005827 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5828 continue;
5829 }
5830 mHandler.post(new Runnable() {
5831 @Override
5832 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005833 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005834 }
5835 });
5836 }
5837 }
5838
Christoph Studer85a384b2014-08-27 20:16:15 +02005839 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005840 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005841 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5842 continue;
5843 }
5844 mHandler.post(new Runnable() {
5845 @Override
5846 public void run() {
5847 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5848 }
5849 });
5850 }
5851 }
5852
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005853 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005854 final NotificationChannel channel, final int modificationType) {
5855 if (channel == null) {
5856 return;
5857 }
5858 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04005859 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005860 continue;
5861 }
Julia Reynolds018aa622017-04-20 11:31:30 -04005862
Eugene Suslaa25d17f2017-08-24 11:28:08 -07005863 BackgroundThread.getHandler().post(() -> {
5864 if (hasCompanionDevice(serviceInfo)) {
5865 notifyNotificationChannelChanged(
5866 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04005867 }
5868 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005869 }
5870 }
5871
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005872 protected void notifyNotificationChannelGroupChanged(
5873 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5874 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005875 if (group == null) {
5876 return;
5877 }
5878 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04005879 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005880 continue;
5881 }
Julia Reynolds018aa622017-04-20 11:31:30 -04005882
Eugene Suslaa25d17f2017-08-24 11:28:08 -07005883 BackgroundThread.getHandler().post(() -> {
5884 if (hasCompanionDevice(serviceInfo)) {
5885 notifyNotificationChannelGroupChanged(
5886 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04005887 }
5888 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005889 }
5890 }
5891
Christoph Studercef37cf2014-07-25 14:18:17 +02005892 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02005893 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04005894 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005895 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04005896 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07005897 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04005898 } catch (RemoteException ex) {
5899 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5900 }
5901 }
5902
Christoph Studercef37cf2014-07-25 14:18:17 +02005903 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04005904 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04005905 if (!info.enabledAndUserMatches(sbn.getUserId())) {
5906 return;
5907 }
Christoph Studer05ad4822014-05-16 14:16:03 +02005908 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005909 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04005910 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04005911 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04005912 } catch (RemoteException ex) {
5913 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04005914 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005915 }
Chris Wrenf9536642014-04-17 10:01:54 -04005916
Christoph Studer05ad4822014-05-16 14:16:03 +02005917 private void notifyRankingUpdate(ManagedServiceInfo info,
5918 NotificationRankingUpdate rankingUpdate) {
5919 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04005920 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02005921 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04005922 } catch (RemoteException ex) {
5923 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5924 }
5925 }
John Spurlock1fa865f2014-07-21 14:56:39 -04005926
John Spurlockd8afe3c2014-08-01 14:04:07 -04005927 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04005928 final INotificationListener listener = (INotificationListener) info.service;
5929 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005930 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005931 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005932 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04005933 }
5934 }
Justin Koh38156c52014-06-04 13:57:49 -07005935
Christoph Studer85a384b2014-08-27 20:16:15 +02005936 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5937 int interruptionFilter) {
5938 final INotificationListener listener = (INotificationListener) info.service;
5939 try {
5940 listener.onInterruptionFilterChanged(interruptionFilter);
5941 } catch (RemoteException ex) {
5942 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5943 }
5944 }
5945
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005946 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005947 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005948 final int modificationType) {
5949 final INotificationListener listener = (INotificationListener) info.service;
5950 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005951 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005952 } catch (RemoteException ex) {
5953 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5954 }
5955 }
5956
5957 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005958 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005959 final int modificationType) {
5960 final INotificationListener listener = (INotificationListener) info.service;
5961 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005962 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005963 } catch (RemoteException ex) {
5964 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5965 }
5966 }
5967
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005968 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07005969 if (packageName == null) {
5970 return false;
5971 }
5972 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005973 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005974 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07005975 if (packageName.equals(serviceInfo.component.getPackageName())) {
5976 return true;
5977 }
5978 }
5979 }
5980 return false;
5981 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005982 }
John Spurlock25e2d242014-06-27 13:58:23 -04005983
5984 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04005985 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04005986 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04005987 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04005988 public long since;
5989 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04005990 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05005991 public boolean proto = false;
John Spurlock25e2d242014-06-27 13:58:23 -04005992
Kweku Adams887f09c2017-11-13 17:12:20 -08005993 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04005994 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04005995 final DumpFilter filter = new DumpFilter();
5996 for (int ai = 0; ai < args.length; ai++) {
5997 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07005998 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05005999 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07006000 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04006001 filter.redact = false;
6002 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
6003 if (ai < args.length-1) {
6004 ai++;
6005 filter.pkgFilter = args[ai].trim().toLowerCase();
6006 if (filter.pkgFilter.isEmpty()) {
6007 filter.pkgFilter = null;
6008 } else {
6009 filter.filtered = true;
6010 }
6011 }
6012 } else if ("--zen".equals(a) || "zen".equals(a)) {
6013 filter.filtered = true;
6014 filter.zen = true;
6015 } else if ("--stats".equals(a)) {
6016 filter.stats = true;
6017 if (ai < args.length-1) {
6018 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01006019 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04006020 } else {
6021 filter.since = 0;
6022 }
6023 }
John Spurlock25e2d242014-06-27 13:58:23 -04006024 }
Dan Sandlera1770312015-07-10 13:59:29 -04006025 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04006026 }
6027
6028 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04006029 if (!filtered) return true;
6030 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04006031 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04006032 }
6033
6034 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04006035 if (!filtered) return true;
6036 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04006037 }
6038
6039 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04006040 if (!filtered) return true;
6041 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04006042 }
6043
6044 @Override
6045 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04006046 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04006047 }
6048 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07006049
6050 /**
6051 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
6052 * binder without sending large amounts of data over a oneway transaction.
6053 */
6054 private static final class StatusBarNotificationHolder
6055 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07006056 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006057
6058 public StatusBarNotificationHolder(StatusBarNotification value) {
6059 mValue = value;
6060 }
6061
Griff Hazene9aac5f2014-09-05 20:04:09 -07006062 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07006063 @Override
6064 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07006065 StatusBarNotification value = mValue;
6066 mValue = null;
6067 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006068 }
6069 }
John Spurlock7c74f782015-06-04 13:01:42 -04006070
Julia Reynoldsb852e562017-06-06 16:14:18 -04006071 private class ShellCmd extends ShellCommand {
6072 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006073 + "allow_listener COMPONENT [user_id]\n"
6074 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006075 + "set_assistant COMPONENT\n"
6076 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04006077 + "allow_dnd PACKAGE\n"
6078 + "disallow_dnd PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04006079
Julia Reynoldsb852e562017-06-06 16:14:18 -04006080 @Override
6081 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07006082 if (cmd == null) {
6083 return handleDefaultCommands(cmd);
6084 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006085 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04006086 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006087 switch (cmd) {
6088 case "allow_dnd": {
6089 getBinderService().setNotificationPolicyAccessGranted(
6090 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04006091 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04006092 break;
6093
6094 case "disallow_dnd": {
6095 getBinderService().setNotificationPolicyAccessGranted(
6096 getNextArgRequired(), false);
6097 }
6098 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006099 case "allow_listener": {
6100 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6101 if (cn == null) {
6102 pw.println("Invalid listener - must be a ComponentName");
6103 return -1;
6104 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006105 String userId = getNextArg();
6106 if (userId == null) {
6107 getBinderService().setNotificationListenerAccessGranted(cn, true);
6108 } else {
6109 getBinderService().setNotificationListenerAccessGrantedForUser(
6110 cn, Integer.parseInt(userId), true);
6111 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006112 }
6113 break;
6114 case "disallow_listener": {
6115 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6116 if (cn == null) {
6117 pw.println("Invalid listener - must be a ComponentName");
6118 return -1;
6119 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006120 String userId = getNextArg();
6121 if (userId == null) {
6122 getBinderService().setNotificationListenerAccessGranted(cn, false);
6123 } else {
6124 getBinderService().setNotificationListenerAccessGrantedForUser(
6125 cn, Integer.parseInt(userId), false);
6126 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006127 }
6128 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006129 case "allow_assistant": {
6130 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6131 if (cn == null) {
6132 pw.println("Invalid assistant - must be a ComponentName");
6133 return -1;
6134 }
6135 getBinderService().setNotificationAssistantAccessGranted(cn, true);
6136 }
6137 break;
6138 case "disallow_assistant": {
6139 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6140 if (cn == null) {
6141 pw.println("Invalid assistant - must be a ComponentName");
6142 return -1;
6143 }
6144 getBinderService().setNotificationAssistantAccessGranted(cn, false);
6145 }
6146 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04006147
6148 default:
6149 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04006150 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006151 } catch (Exception e) {
6152 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04006153 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04006154 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04006155 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04006156 }
6157
Julia Reynoldsb852e562017-06-06 16:14:18 -04006158 @Override
6159 public void onHelp() {
6160 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04006161 }
6162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006163}