blob: a693e9747db287fb31942802c0b8088977a44f7d [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 Reynolds7c96b582017-05-25 12:35:36 -040019import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040020import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050021import static android.content.pm.PackageManager.FEATURE_LEANBACK;
22import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynolds4db59552017-06-30 13:34:01 -040023import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Julia Reynolds88a879f2017-07-26 17:06:46 -040024import static android.os.UserHandle.USER_NULL;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040025import static android.service.notification.NotificationListenerService
26 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
27import static android.service.notification.NotificationListenerService
28 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
29import static android.service.notification.NotificationListenerService
30 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050031import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
32import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
33import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040034import static android.service.notification.NotificationListenerService.REASON_CANCEL;
35import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
36import static android.service.notification.NotificationListenerService.REASON_CLICK;
37import static android.service.notification.NotificationListenerService.REASON_ERROR;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050038import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
39import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
40import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
41import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
42import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
43import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
44import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
45import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050046import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050047import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
48import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Jason Monk63506742015-12-16 12:06:51 -050049import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
Bryce Lee7219ada2016-04-08 10:54:23 -070050import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
51import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
Julia Reynoldsd5607292016-02-05 15:25:58 -050052import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
Julia Reynolds61721582016-01-05 08:35:25 -050053import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
Christoph Studerb82bc782014-08-20 14:29:43 +020054import static android.service.notification.NotificationListenerService.TRIM_FULL;
55import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070056
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070057import static android.view.Display.DEFAULT_DISPLAY;
58import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070059
Chris Wren51017d02015-12-15 15:34:46 -050060import android.Manifest;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040061import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080062import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070063import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070064import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050065import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040066import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050067import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040068import android.app.AutomaticZenRule;
Julia Reynolds59e152e2017-01-25 17:42:53 -050069import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -050070import android.app.backup.BackupManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.app.IActivityManager;
72import android.app.INotificationManager;
73import android.app.ITransientNotification;
74import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040075import android.app.NotificationChannel;
John Spurlock1fc476d2015-04-14 16:05:20 -040076import android.app.NotificationManager.Policy;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -050077import android.app.NotificationManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.app.PendingIntent;
79import android.app.StatusBarManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070080import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070081import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040082import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070084import android.content.ComponentName;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070085import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.content.Context;
87import android.content.Intent;
88import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040089import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +000090import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.content.pm.PackageManager;
92import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +020093import android.content.pm.ParceledListSlice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070095import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -040096import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -070097import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -050098import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -070099import android.media.IRingtonePlayer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400102import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400103import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400104import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400106import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import android.os.IBinder;
John Spurlock7340fc82014-04-24 18:50:12 -0400108import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400109import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700111import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700112import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400113import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400114import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400115import android.os.ShellCallback;
116import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400117import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100118import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700119import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import android.os.Vibrator;
Michael Wright71216972017-01-31 18:33:54 +0000121import android.os.VibrationEffect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400123import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400124import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400125import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400126import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700127import android.service.notification.IStatusBarNotificationHolder;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500128import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400129import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200130import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500131import android.service.notification.NotificationRecordProto;
132import android.service.notification.NotificationServiceDumpProto;
133import android.service.notification.NotificationServiceProto;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500134import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700135import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400136import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500137import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400138import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500139import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700140import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400141import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400142import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700143import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800145import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700146import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400147import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500148import android.util.proto.ProtoOutputStream;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700149import android.view.WindowManagerInternal;
svetoslavganov75986cf2009-05-14 22:28:01 -0700150import android.view.accessibility.AccessibilityEvent;
151import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000153
Scott Greenwald9a05b312013-06-28 00:37:54 -0400154import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400155import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400156import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500157import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500158import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500159import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Chris Wrend1dbc922015-06-19 17:51:16 -0400160import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400161import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600162import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400163import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400164import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400165import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700166import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800167import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700168import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800169import com.android.server.SystemService;
170import com.android.server.lights.Light;
171import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400172import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700173import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400174import com.android.server.statusbar.StatusBarManagerInternal;
Ruben Brunke24b9a62016-02-16 21:38:24 -0800175import com.android.server.notification.ManagedServices.UserProfiles;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800176
John Spurlockb408e8e2014-04-23 21:12:45 -0400177import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000178
Chris Wrene4b38802015-07-07 15:54:19 -0400179import org.json.JSONException;
180import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700181import org.xmlpull.v1.XmlPullParser;
182import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400183import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700184
John Spurlock35ef0a62015-05-28 11:24:10 -0400185import java.io.ByteArrayInputStream;
186import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400187import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400189import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400190import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400191import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400192import java.io.InputStream;
193import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194import java.io.PrintWriter;
Beverly5d463b62017-07-26 14:13:40 -0400195import java.net.URI;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100196import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500197import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000199import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500200import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400201import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200202import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500203import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400204import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500205import java.util.concurrent.TimeUnit;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400206
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400207/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800208public class NotificationManagerService extends SystemService {
209 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100210 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800211 public static final boolean ENABLE_CHILD_NOTIFICATIONS
212 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213
Adam Lesinski182f73f2013-12-05 16:48:06 -0800214 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400215 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 // message codes
Adam Lesinski182f73f2013-12-05 16:48:06 -0800218 static final int MESSAGE_TIMEOUT = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400219 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500220 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
221 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
222 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
223
224 // ranking thread messages
225 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
226 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700228 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800229 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800230
Adam Lesinski182f73f2013-12-05 16:48:06 -0800231 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200232
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500233 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
234
Adam Lesinski182f73f2013-12-05 16:48:06 -0800235 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
Adam Lesinski182f73f2013-12-05 16:48:06 -0800237 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500238
Adam Lesinski182f73f2013-12-05 16:48:06 -0800239 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400240
Christoph Studer12aeda82014-09-23 19:08:56 +0200241 // When #matchesCallFilter is called from the ringer, wait at most
242 // 3s to resolve the contacts. This timeout is required since
243 // ContactsProvider might take a long time to start up.
244 //
245 // Return STARRED_CONTACT when the timeout is hit in order to avoid
246 // missed calls in ZEN mode "Important".
247 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
248 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
249 ValidateNotificationPeople.STARRED_CONTACT;
250
Christoph Studer265c1052014-07-23 17:14:33 +0200251 /** notification_enqueue status value for a newly enqueued notification. */
252 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
253
254 /** notification_enqueue status value for an existing notification. */
255 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
256
257 /** notification_enqueue status value for an ignored notification. */
258 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400259 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200260
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500261 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
262
Julia Reynolds2a128742016-11-28 14:29:25 -0500263 private static final String ACTION_NOTIFICATION_TIMEOUT =
264 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
265 private static final int REQUEST_CODE_TIMEOUT = 1;
266 private static final String SCHEME_TIMEOUT = "timeout";
267 private static final String EXTRA_KEY = "key";
268
Adam Lesinski182f73f2013-12-05 16:48:06 -0800269 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400270 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500271 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500272 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800273 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500274 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800275 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800276 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700277 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500278 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400279 private ICompanionDeviceManager mCompanionManager;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400282 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400283 private final HandlerThread mRankingThread = new HandlerThread("ranker",
284 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
Adam Lesinski182f73f2013-12-05 16:48:06 -0800286 private Light mNotificationLight;
287 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800288
Daniel Sandleredbb3802012-11-13 20:49:47 -0800289 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400290 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800291 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800292
John Spurlockd8afe3c2014-08-01 14:04:07 -0400293 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400294 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500295 private String mSoundNotificationKey;
296 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297
Bryce Lee7219ada2016-04-08 10:54:23 -0700298 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400299 new SparseArray<>();
300 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400301 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500302 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400303
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500304 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400305 private boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400306 protected boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500307 private boolean mNotificationPulseEnabled;
308
Beverly5d463b62017-07-26 14:13:40 -0400309 private Uri mInCallNotificationUri;
310 private AudioAttributes mInCallNotificationAudioAttributes;
311 private float mInCallNotificationVolume;
Marta Białka39c992f2011-03-10 10:27:24 +0100312
Daniel Sandler09a247e2013-02-14 10:24:17 -0500313 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500314 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400315 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400316 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400317 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400318 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400319 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500320 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400321 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400322 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400323 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200324 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325
Chris Wren6054e612014-11-25 17:16:46 -0500326 // The last key in this list owns the hardware.
327 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700328
Adam Lesinski182f73f2013-12-05 16:48:06 -0800329 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700330 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500331
Griff Hazen9f637d12014-06-10 11:13:51 -0700332 private Archive mArchive;
333
John Spurlock21258a32015-05-27 18:22:55 -0400334 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400335 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400336
Daniel Sandler0da673f2012-04-11 12:33:16 -0400337 private static final int DB_VERSION = 1;
338
John Spurlock21258a32015-05-27 18:22:55 -0400339 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400340 private static final String ATTR_VERSION = "version";
341
Chris Wren54bbef42014-07-09 18:37:56 -0400342 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400343
John Spurlockb408e8e2014-04-23 21:12:45 -0400344 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400345 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400346 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400347 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200348 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100349
John Spurlocke6a7d932014-03-13 12:29:00 -0400350 private static final int MY_UID = Process.myUid();
351 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700352 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500353 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400354 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400355 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400356
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400357 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400358 private GroupHelper mGroupHelper;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500359 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400360
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500361 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700362 final int mBufferSize;
363 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500364
Griff Hazen9f637d12014-06-10 11:13:51 -0700365 public Archive(int size) {
366 mBufferSize = size;
367 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500368 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700369
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400370 public String toString() {
371 final StringBuilder sb = new StringBuilder();
372 final int N = mBuffer.size();
373 sb.append("Archive (");
374 sb.append(N);
375 sb.append(" notification");
376 sb.append((N==1)?")":"s)");
377 return sb.toString();
378 }
379
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500380 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700381 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500382 mBuffer.removeFirst();
383 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400384
385 // We don't want to store the heavy bits of the notification in the archive,
386 // but other clients in the system process might be using the object, so we
387 // store a (lightened) copy.
388 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500389 }
390
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500391 public Iterator<StatusBarNotification> descendingIterator() {
392 return mBuffer.descendingIterator();
393 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500394
395 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700396 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500397 final StatusBarNotification[] a
398 = new StatusBarNotification[Math.min(count, mBuffer.size())];
399 Iterator<StatusBarNotification> iter = descendingIterator();
400 int i=0;
401 while (iter.hasNext() && i < count) {
402 a[i++] = iter.next();
403 }
404 return a;
405 }
406
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500407 }
408
Julia Reynolds88a879f2017-07-26 17:06:46 -0400409 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400410 String defaultListenerAccess = getContext().getResources().getString(
411 com.android.internal.R.string.config_defaultListenerAccessPackages);
412 if (defaultListenerAccess != null) {
413 for (String whitelisted :
414 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
415 // Gather all notification listener components for candidate pkgs.
416 Set<ComponentName> approvedListeners =
417 mListeners.queryPackageForServices(whitelisted,
418 PackageManager.MATCH_DIRECT_BOOT_AWARE
419 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
420 for (ComponentName cn : approvedListeners) {
421 try {
422 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
423 userId, true);
424 } catch (RemoteException e) {
425 e.printStackTrace();
426 }
427 }
428 }
429 }
430 String defaultDndAccess = getContext().getResources().getString(
431 com.android.internal.R.string.config_defaultDndAccessPackages);
432 if (defaultListenerAccess != null) {
433 for (String whitelisted :
434 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
435 try {
436 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
437 } catch (RemoteException e) {
438 e.printStackTrace();
439 }
440 }
441 }
442 }
443
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400444 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400445 throws XmlPullParserException, NumberFormatException, IOException {
446 final XmlPullParser parser = Xml.newPullParser();
447 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400448 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
449 boolean migratedManagedServices = false;
450 int outerDepth = parser.getDepth();
451 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
452 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
453 mZenModeHelper.readXml(parser, forRestore);
454 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
455 mRankingHelper.readXml(parser, forRestore);
456 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400457 // No non-system managed services are allowed on low ram devices
458 if (!ActivityManager.isLowRamDeviceStatic()) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400459 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
460 mListeners.readXml(parser);
461 migratedManagedServices = true;
462 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
463 mAssistants.readXml(parser);
464 migratedManagedServices = true;
465 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
466 mConditionProviders.readXml(parser);
467 migratedManagedServices = true;
468 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400469 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400470 }
471
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400472 if (!migratedManagedServices) {
473 mListeners.migrateToXml();
474 mAssistants.migrateToXml();
475 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400476 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400477 }
478 }
479
John Spurlock056c5192014-04-20 21:52:01 -0400480 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400481 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500482 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400483
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400484 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400485 try {
486 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400487 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400488 } catch (FileNotFoundException e) {
489 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400490 // Load default managed services approvals
Julia Reynolds88a879f2017-07-26 17:06:46 -0400491 readDefaultApprovedServices(UserHandle.USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400492 } catch (IOException e) {
493 Log.wtf(TAG, "Unable to read notification policy", e);
494 } catch (NumberFormatException e) {
495 Log.wtf(TAG, "Unable to parse notification policy", e);
496 } catch (XmlPullParserException e) {
497 Log.wtf(TAG, "Unable to parse notification policy", e);
498 } finally {
499 IoUtils.closeQuietly(infile);
500 }
501 }
502 }
503
504 public void savePolicyFile() {
505 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
506 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
507 }
508
509 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400510 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400511 synchronized (mPolicyFile) {
512 final FileOutputStream stream;
513 try {
514 stream = mPolicyFile.startWrite();
515 } catch (IOException e) {
516 Slog.w(TAG, "Failed to save policy file", e);
517 return;
518 }
519
520 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400521 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400522 mPolicyFile.finishWrite(stream);
523 } catch (IOException e) {
524 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
525 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400526 }
527 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400528 BackupManager.dataChanged(getContext().getPackageName());
529 }
530
531 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
532 final XmlSerializer out = new FastXmlSerializer();
533 out.setOutput(stream, StandardCharsets.UTF_8.name());
534 out.startDocument(null, true);
535 out.startTag(null, TAG_NOTIFICATION_POLICY);
536 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
537 mZenModeHelper.writeXml(out, forBackup);
538 mRankingHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400539 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400540 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400541 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400542 out.endTag(null, TAG_NOTIFICATION_POLICY);
543 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400544 }
545
Chris Wren66189fc2015-06-25 14:04:33 -0400546 /** Use this to check if a package can post a notification or toast. */
547 private boolean checkNotificationOp(String pkg, int uid) {
548 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000549 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
Chris Wren66189fc2015-06-25 14:04:33 -0400550 }
551
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 private static final class ToastRecord
553 {
554 final int pid;
555 final String pkg;
Beverly4ee785b2017-08-11 12:49:56 -0400556 ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700558 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700560 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
561 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 this.pid = pid;
563 this.pkg = pkg;
564 this.callback = callback;
565 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700566 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568
569 void update(int duration) {
570 this.duration = duration;
571 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800572
Beverly4ee785b2017-08-11 12:49:56 -0400573 void update(ITransientNotification callback) {
574 this.callback = callback;
575 }
576
John Spurlock25e2d242014-06-27 13:58:23 -0400577 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
578 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 pw.println(prefix + this);
580 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 @Override
583 public final String toString()
584 {
585 return "ToastRecord{"
586 + Integer.toHexString(System.identityHashCode(this))
587 + " pkg=" + pkg
588 + " callback=" + callback
589 + " duration=" + duration;
590 }
591 }
592
Beverly40239d92017-07-07 10:20:41 -0400593 @VisibleForTesting
594 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595
Adam Lesinski182f73f2013-12-05 16:48:06 -0800596 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500598 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400599 mDisableNotificationEffects =
600 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400601 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 // cancel whatever's going on
603 long identity = Binder.clearCallingIdentity();
604 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800605 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700606 if (player != null) {
607 player.stopAsync();
608 }
609 } catch (RemoteException e) {
610 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 Binder.restoreCallingIdentity(identity);
612 }
613
614 identity = Binder.clearCallingIdentity();
615 try {
616 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700617 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 Binder.restoreCallingIdentity(identity);
619 }
620 }
621 }
622 }
623
Adam Lesinski182f73f2013-12-05 16:48:06 -0800624 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400625 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500626 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400627 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000628 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 }
631
Adam Lesinski182f73f2013-12-05 16:48:06 -0800632 @Override
Christoph Studer03b87a22014-04-30 17:33:27 +0200633 public void onNotificationClick(int callingUid, int callingPid, String key) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500634 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200635 NotificationRecord r = mNotificationsByKey.get(key);
636 if (r == null) {
637 Log.w(TAG, "No notification with key: " + key);
638 return;
639 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400640 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500641 MetricsLogger.action(r.getLogMaker(now)
642 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
643 .setType(MetricsEvent.TYPE_ACTION));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400644 EventLogTags.writeNotificationClicked(key,
645 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
646
Christoph Studer03b87a22014-04-30 17:33:27 +0200647 StatusBarNotification sbn = r.sbn;
648 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
649 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
650 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400651 REASON_CLICK, null);
Christoph Studer03b87a22014-04-30 17:33:27 +0200652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654
Adam Lesinski182f73f2013-12-05 16:48:06 -0800655 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200656 public void onNotificationActionClick(int callingUid, int callingPid, String key,
657 int actionIndex) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500658 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200659 NotificationRecord r = mNotificationsByKey.get(key);
660 if (r == null) {
661 Log.w(TAG, "No notification with key: " + key);
662 return;
663 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400664 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500665 MetricsLogger.action(r.getLogMaker(now)
666 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
667 .setType(MetricsEvent.TYPE_ACTION)
668 .setSubtype(actionIndex));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400669 EventLogTags.writeNotificationActionClicked(key, actionIndex,
670 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Christoph Studer4da84cd2014-10-21 17:24:20 +0200671 // TODO: Log action click via UsageStats.
672 }
673 }
674
675 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400676 public void onNotificationClear(int callingUid, int callingPid,
677 String pkg, String tag, int id, int userId) {
678 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000679 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400680 true, userId, REASON_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400681 }
682
Adam Lesinski182f73f2013-12-05 16:48:06 -0800683 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400684 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500685 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400686 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400687 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100688 if (clearEffects) {
689 clearEffects();
690 }
691 }
692
693 @Override
694 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500695 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100696 EventLogTags.writeNotificationPanelHidden();
697 }
698
699 @Override
700 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500701 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100702 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400703 clearSoundLocked();
704 clearVibrateLocked();
705 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 }
707 }
Joe Onorato005847b2010-06-04 16:08:02 -0400708
Adam Lesinski182f73f2013-12-05 16:48:06 -0800709 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400710 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000711 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400712 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
713 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400714 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400715 REASON_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700716 long ident = Binder.clearCallingIdentity();
717 try {
Christopher Tate8aa8fe12017-01-20 17:50:32 -0800718 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700719 "Bad notification posted from package " + pkg
720 + ": " + message);
721 } catch (RemoteException e) {
722 }
723 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400724 }
John Spurlocke677d712014-02-13 12:52:19 -0500725
726 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400727 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
728 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500729 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400730 for (NotificationVisibility nv : newlyVisibleKeys) {
731 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200732 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400733 r.setVisibility(true, nv.rank);
734 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200735 }
736 // Note that we might receive this event after notifications
737 // have already left the system, e.g. after dismissing from the
738 // shade. Hence not finding notifications in
739 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400740 for (NotificationVisibility nv : noLongerVisibleKeys) {
741 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200742 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400743 r.setVisibility(false, nv.rank);
744 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200745 }
746 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200747 }
Chris Wren78403d72014-07-28 10:23:24 +0100748
749 @Override
750 public void onNotificationExpansionChanged(String key,
751 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500752 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100753 NotificationRecord r = mNotificationsByKey.get(key);
754 if (r != null) {
755 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400756 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500757 MetricsLogger.action(r.getLogMaker(now)
758 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
759 .setType(MetricsEvent.TYPE_DETAIL));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400760 EventLogTags.writeNotificationExpansion(key,
761 userAction ? 1 : 0, expanded ? 1 : 0,
762 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100763 }
764 }
765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 };
767
Julia Reynolds88860ce2017-06-01 16:55:49 -0400768 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400769 private void clearSoundLocked() {
770 mSoundNotificationKey = null;
771 long identity = Binder.clearCallingIdentity();
772 try {
773 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
774 if (player != null) {
775 player.stopAsync();
776 }
777 } catch (RemoteException e) {
778 } finally {
779 Binder.restoreCallingIdentity(identity);
780 }
781 }
782
Julia Reynolds88860ce2017-06-01 16:55:49 -0400783 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400784 private void clearVibrateLocked() {
785 mVibrateNotificationKey = null;
786 long identity = Binder.clearCallingIdentity();
787 try {
788 mVibrator.cancel();
789 } finally {
790 Binder.restoreCallingIdentity(identity);
791 }
792 }
793
Julia Reynolds88860ce2017-06-01 16:55:49 -0400794 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400795 private void clearLightsLocked() {
796 // light
797 mLights.clear();
798 updateLightsLocked();
799 }
800
Beverlyd4f96492017-08-02 13:36:11 -0400801 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
802 @Override
803 public void onReceive(Context context, Intent intent) {
804 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
805 mZenModeHelper.updateDefaultZenRules();
Julia Reynolds816797a2017-08-11 15:47:09 -0400806 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400807 }
808 }
809 };
810
Julia Reynoldsb852e562017-06-06 16:14:18 -0400811 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
812 @Override
813 public void onReceive(Context context, Intent intent) {
814 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
815 try {
816 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
817 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100818 int restoredFromSdkInt = intent.getIntExtra(
819 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400820 mListeners.onSettingRestored(
821 element, newValue, restoredFromSdkInt, getSendingUserId());
822 mConditionProviders.onSettingRestored(
823 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400824 } catch (Exception e) {
825 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
826 }
827 }
828 }
829 };
830
Julia Reynolds2a128742016-11-28 14:29:25 -0500831 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
832 @Override
833 public void onReceive(Context context, Intent intent) {
834 String action = intent.getAction();
835 if (action == null) {
836 return;
837 }
838 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
839 final NotificationRecord record;
840 synchronized (mNotificationLock) {
841 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
842 }
843 if (record != null) {
844 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
845 record.sbn.getPackageName(), record.sbn.getTag(),
846 record.sbn.getId(), 0,
847 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
848 REASON_TIMEOUT, null);
849 }
850 }
851 }
852 };
853
Kenny Guy70058402014-10-28 20:45:06 +0000854 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 @Override
856 public void onReceive(Context context, Intent intent) {
857 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -0800858 if (action == null) {
859 return;
860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800862 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -0400863 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -0400864 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -0400865 boolean cancelNotifications = true;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000866 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -0400867
Chris Wren3da73022013-05-10 14:41:21 -0400868 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -0400869 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800870 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -0400871 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800872 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000873 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
874 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +0000875 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
876 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800877 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500878 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -0400879 boolean removingPackage = queryRemove &&
880 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
881 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800882 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800883 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500884 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000885 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
886 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
887 reason = REASON_PACKAGE_SUSPENDED;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800888 } else if (queryRestart) {
889 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500890 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800891 } else {
892 Uri uri = intent.getData();
893 if (uri == null) {
894 return;
895 }
896 String pkgName = uri.getSchemeSpecificPart();
897 if (pkgName == null) {
898 return;
899 }
Daniel Sandler26ece572012-06-01 15:38:46 -0400900 if (packageChanged) {
901 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -0700902 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500903 final int enabled = mPackageManager.getApplicationEnabledSetting(
904 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +0000905 changeUserId != UserHandle.USER_ALL ? changeUserId :
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500906 UserHandle.USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -0700907 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
908 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
909 cancelNotifications = false;
910 }
911 } catch (IllegalArgumentException e) {
912 // Package doesn't exist; probably racing with uninstall.
913 // cancelNotifications is already true, so nothing to do here.
914 if (DBG) {
915 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
916 }
Kenny Guy70058402014-10-28 20:45:06 +0000917 } catch (RemoteException e) {
918 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -0400919 }
920 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800921 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500922 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800924 if (pkgList != null && (pkgList.length > 0)) {
925 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -0400926 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400927 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
928 !queryRestart, changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -0400929 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400932 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400933 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400934 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500935 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
936 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +0000937 }
938 }
939 };
940
941 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
942 @Override
943 public void onReceive(Context context, Intent intent) {
944 String action = intent.getAction();
945
946 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400947 // Keep track of screen on/off state, but do not turn off the notification light
948 // until user passes through the lock screen or views the notification.
949 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +0100950 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400951 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
952 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +0100953 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500954 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -0500955 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
956 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500957 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700958 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
959 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
960 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400961 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500962 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700963 }
Rubin Xue95057a2016-04-01 16:49:25 +0100964 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000965 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +0100966 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400967 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500968 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000969 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400970 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
971 // turn off LED when user passes through lock screen
972 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400973 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400974 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400975 // reload per-user settings
976 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -0400977 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200978 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -0400979 mConditionProviders.onUserSwitched(user);
980 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400981 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -0400982 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000983 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400984 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
985 if (userId != USER_NULL) {
986 mUserProfiles.updateCache(context);
987 readDefaultApprovedServices(userId);
988 }
John Spurlock21258a32015-05-27 18:22:55 -0400989 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400990 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
John Spurlock21258a32015-05-27 18:22:55 -0400991 mZenModeHelper.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -0400992 mRankingHelper.onUserRemoved(user);
993 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500994 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400995 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500996 mConditionProviders.onUserUnlocked(user);
997 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400998 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500999 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 }
1001 }
1002 };
1003
John Spurlock7c74f782015-06-04 13:01:42 -04001004 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001005 private final Uri NOTIFICATION_BADGING_URI
1006 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001007 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1008 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001009 private final Uri NOTIFICATION_RATE_LIMIT_URI
1010 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001011
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001012 SettingsObserver(Handler handler) {
1013 super(handler);
1014 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001015
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001016 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001017 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001018 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1019 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001020 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001021 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001022 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1023 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001024 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001025 }
1026
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001027 @Override public void onChange(boolean selfChange, Uri uri) {
1028 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001029 }
1030
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001031 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001032 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001033 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001034 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1035 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001036 if (mNotificationPulseEnabled != pulseEnabled) {
1037 mNotificationPulseEnabled = pulseEnabled;
1038 updateNotificationPulse();
1039 }
1040 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001041 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1042 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1043 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1044 }
Chris Wren89aa2262017-05-05 18:05:56 -04001045 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1046 mRankingHelper.updateBadgingEnabled();
1047 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001048 }
1049 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001050
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001051 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001052 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001053
Daniel Sandleredbb3802012-11-13 20:49:47 -08001054 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1055 int[] ar = r.getIntArray(resid);
1056 if (ar == null) {
1057 return def;
1058 }
1059 final int len = ar.length > maxlen ? maxlen : ar.length;
1060 long[] out = new long[len];
1061 for (int i=0; i<len; i++) {
1062 out[i] = ar[i];
1063 }
1064 return out;
1065 }
1066
Jeff Brownb880d882014-02-10 19:47:07 -08001067 public NotificationManagerService(Context context) {
1068 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001069 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001070 }
1071
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001072 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001073 @VisibleForTesting
1074 void setAudioManager(AudioManager audioMananger) {
1075 mAudioManager = audioMananger;
1076 }
1077
1078 @VisibleForTesting
1079 void setVibrator(Vibrator vibrator) {
1080 mVibrator = vibrator;
1081 }
1082
1083 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001084 void setLights(Light light) {
1085 mNotificationLight = light;
1086 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001087 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001088 }
1089
1090 @VisibleForTesting
1091 void setScreenOn(boolean on) {
1092 mScreenOn = on;
1093 }
1094
1095 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001096 int getNotificationRecordCount() {
1097 synchronized (mNotificationLock) {
1098 int count = mNotificationList.size() + mNotificationsByKey.size()
1099 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1100 // subtract duplicates
1101 for (NotificationRecord posted : mNotificationList) {
1102 if (mNotificationsByKey.containsKey(posted.getKey())) {
1103 count--;
1104 }
1105 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001106 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001107 }
1108 }
1109
1110 return count;
1111 }
1112 }
1113
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001114 void clearNotifications() {
1115 mEnqueuedNotifications.clear();
1116 mNotificationList.clear();
1117 mNotificationsByKey.clear();
1118 mSummaryByGroupKey.clear();
1119 }
1120
Julia Reynolds080361e2017-07-13 11:23:12 -04001121 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001122 void addNotification(NotificationRecord r) {
1123 mNotificationList.add(r);
1124 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001125 if (r.sbn.isGroup()) {
1126 mSummaryByGroupKey.put(r.getGroupKey(), r);
1127 }
1128 }
1129
1130 @VisibleForTesting
1131 void addEnqueuedNotification(NotificationRecord r) {
1132 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001133 }
1134
1135 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001136 void setSystemReady(boolean systemReady) {
1137 mSystemReady = systemReady;
1138 }
1139
1140 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001141 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001142 mHandler = handler;
1143 }
1144
Chris Wrend4054312016-06-24 17:07:40 -04001145 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001146 void setFallbackVibrationPattern(long[] vibrationPattern) {
1147 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001148 }
1149
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001150 @VisibleForTesting
1151 void setPackageManager(IPackageManager packageManager) {
1152 mPackageManager = packageManager;
1153 }
1154
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001155 @VisibleForTesting
1156 void setRankingHelper(RankingHelper rankingHelper) {
1157 mRankingHelper = rankingHelper;
1158 }
1159
1160 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001161 void setRankingHandler(RankingHandler rankingHandler) {
1162 mRankingHandler = rankingHandler;
1163 }
1164
1165 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001166 void setIsTelevision(boolean isTelevision) {
1167 mIsTelevision = isTelevision;
1168 }
1169
Julia Reynolds76c096d2017-06-19 08:16:04 -04001170 @VisibleForTesting
1171 void setUsageStats(NotificationUsageStats us) {
1172 mUsageStats = us;
1173 }
1174
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001175 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001176 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001177 void init(Looper looper, IPackageManager packageManager,
1178 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001179 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001180 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001181 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001182 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds8aebf352017-06-26 11:35:33 -04001183 ActivityManager activityManager, GroupHelper groupHelper) {
Chris Wren54bbef42014-07-09 18:37:56 -04001184 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001185 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1186 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1187 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1188
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001189 mAm = ActivityManager.getService();
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001190 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001191 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001192 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1193 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001194 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Julia Reynolds2a128742016-11-28 14:29:25 -05001195 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001196 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001197 mActivityManager = activityManager;
San Mehat3ee13172010-02-04 20:54:43 -08001198
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001199 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001200 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001201 String[] extractorNames;
1202 try {
1203 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1204 } catch (Resources.NotFoundException e) {
1205 extractorNames = new String[0];
1206 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001207 mUsageStats = usageStats;
Chris Wren51017d02015-12-15 15:34:46 -05001208 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Chris Wren54bbef42014-07-09 18:37:56 -04001209 mRankingHelper = new RankingHelper(getContext(),
Julia Reynolds85769912016-10-25 09:08:57 -04001210 getContext().getPackageManager(),
Chris Wren51017d02015-12-15 15:34:46 -05001211 mRankingHandler,
Chris Wren5eab2b72015-06-16 13:56:22 -04001212 mUsageStats,
Chris Wren54bbef42014-07-09 18:37:56 -04001213 extractorNames);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001214 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001215 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001216 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001217 @Override
1218 public void onConfigChanged() {
1219 savePolicyFile();
1220 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001221
1222 @Override
1223 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001224 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001225 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001226 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1227 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001228 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001229 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001230 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001231 }
1232 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001233
1234 @Override
1235 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001236 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1237 }
John Spurlock056c5192014-04-20 21:52:01 -04001238 });
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001239 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001240 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001241
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001242 // This is a ManagedServices object that keeps track of the listeners.
1243 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001244
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001245 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001246 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001247
1248 mPolicyFile = policyFile;
1249 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001250
Adam Lesinski182f73f2013-12-05 16:48:06 -08001251 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001252 if (mStatusBar != null) {
1253 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001256 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1257 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001258
Daniel Sandleredbb3802012-11-13 20:49:47 -08001259 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001260 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001261 VIBRATE_PATTERN_MAXLEN,
1262 DEFAULT_VIBRATE_PATTERN);
1263
Beverly5d463b62017-07-26 14:13:40 -04001264 mInCallNotificationUri = Uri.parse("file://" +
1265 resources.getString(R.string.config_inCallNotificationSound));
1266 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1267 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1268 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1269 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
1270 .build();
1271 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1272
Chris Wren5116a822014-06-04 15:59:50 -04001273 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1274
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001275 // Don't start allowing notifications until the setup wizard has run once.
1276 // After that, including subsequent boots, init with notifications turned on.
1277 // This works on the first boot because the setup wizard will toggle this
1278 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001279 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001280 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001281 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001282 }
John Spurlockb2278d62015-04-07 12:47:12 -04001283 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001284 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001285
John Spurlockb408e8e2014-04-23 21:12:45 -04001286 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001287 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001288
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001289 mSettingsObserver = new SettingsObserver(mHandler);
1290
1291 mArchive = new Archive(resources.getInteger(
1292 R.integer.config_notificationServiceArchiveSize));
1293
1294 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1295 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1296 }
1297
1298 @Override
1299 public void onStart() {
1300 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1301 @Override
1302 public void repost(int userId, NotificationRecord r) {
1303 try {
1304 if (DBG) {
1305 Slog.d(TAG, "Reposting " + r.getKey());
1306 }
1307 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1308 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1309 r.sbn.getNotification(), userId);
1310 } catch (Exception e) {
1311 Slog.e(TAG, "Cannot un-snooze notification", e);
1312 }
1313 }
1314 }, mUserProfiles);
1315
1316 final File systemDir = new File(Environment.getDataDirectory(), "system");
1317
1318 init(Looper.myLooper(),
1319 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1320 getLocalService(LightsManager.class),
1321 new NotificationListeners(AppGlobals.getPackageManager()),
1322 new NotificationAssistants(AppGlobals.getPackageManager()),
1323 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1324 null, snoozeHelper, new NotificationUsageStats(getContext()),
1325 new AtomicFile(new File(systemDir, "notification_policy.xml")),
1326 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1327 getGroupHelper());
1328
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001329 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001331 filter.addAction(Intent.ACTION_SCREEN_ON);
1332 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001333 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001334 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001335 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001336 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001337 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001338 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001339 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001340 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001341 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001342
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001343 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001344 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001345 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001346 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001347 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1348 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1349 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001350 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1351 null);
1352
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001353 IntentFilter suspendedPkgFilter = new IntentFilter();
1354 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1355 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1356 suspendedPkgFilter, null, null);
1357
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001358 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001359 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1360 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001361
Julia Reynolds2a128742016-11-28 14:29:25 -05001362 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1363 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1364 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1365
Julia Reynoldsb852e562017-06-06 16:14:18 -04001366 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1367 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1368
Beverlyd4f96492017-08-02 13:36:11 -04001369 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1370 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1371
Adam Lesinski182f73f2013-12-05 16:48:06 -08001372 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1373 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 }
1375
Julia Reynolds8aebf352017-06-26 11:35:33 -04001376 private GroupHelper getGroupHelper() {
1377 return new GroupHelper(new GroupHelper.Callback() {
1378 @Override
1379 public void addAutoGroup(String key) {
1380 synchronized (mNotificationLock) {
1381 addAutogroupKeyLocked(key);
1382 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001383 }
1384
1385 @Override
1386 public void removeAutoGroup(String key) {
1387 synchronized (mNotificationLock) {
1388 removeAutogroupKeyLocked(key);
1389 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001390 }
1391
1392 @Override
1393 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1394 createAutoGroupSummary(userId, pkg, triggeringKey);
1395 }
1396
1397 @Override
1398 public void removeAutoGroupSummary(int userId, String pkg) {
1399 synchronized (mNotificationLock) {
1400 clearAutogroupSummaryLocked(userId, pkg);
1401 }
1402 }
1403 });
1404 }
1405
John Spurlocke7a835b2015-05-13 10:47:05 -04001406 private void sendRegisteredOnlyBroadcast(String action) {
1407 getContext().sendBroadcastAsUser(new Intent(action)
1408 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1409 }
1410
Adam Lesinski182f73f2013-12-05 16:48:06 -08001411 @Override
1412 public void onBootPhase(int phase) {
1413 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1414 // no beeping until we're basically done booting
1415 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001416
Adam Lesinski182f73f2013-12-05 16:48:06 -08001417 // Grab our optional AudioService
1418 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001419 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001420 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001421 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001422 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1423 // This observer will force an update when observe is called, causing us to
1424 // bind to listener services.
1425 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001426 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001427 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001428 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 }
1430 }
1431
Julia Reynolds88860ce2017-06-01 16:55:49 -04001432 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001433 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001434 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001435 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001436 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001437 mListenerHints = hints;
1438 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001439 }
1440
Julia Reynolds88860ce2017-06-01 16:55:49 -04001441 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001442 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001443 final long updatedSuppressedEffects = calculateSuppressedEffects();
1444 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1445 final List<ComponentName> suppressors = getSuppressors();
1446 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1447 mEffectsSuppressors = suppressors;
1448 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001449 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001450 }
1451
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001452 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1453 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001454 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1455 // cancel
1456 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1457 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1458 null);
1459 }
Julia Reynolds60315332017-04-04 14:29:07 -04001460 mRankingHelper.updateNotificationChannel(pkg, uid, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001461
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001462 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001463 final NotificationChannel modifiedChannel =
1464 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001465 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001466 pkg, UserHandle.getUserHandleForUid(uid),
1467 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001468 }
1469
Julia Reynolds924eed12017-01-19 09:52:07 -05001470 savePolicyFile();
1471 }
1472
Bryce Lee7219ada2016-04-08 10:54:23 -07001473 private ArrayList<ComponentName> getSuppressors() {
1474 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1475 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1476 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1477
1478 for (ManagedServiceInfo info : serviceInfoList) {
1479 names.add(info.component);
1480 }
1481 }
1482
1483 return names;
1484 }
1485
1486 private boolean removeDisabledHints(ManagedServiceInfo info) {
1487 return removeDisabledHints(info, 0);
1488 }
1489
1490 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1491 boolean removed = false;
1492
1493 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1494 final int hint = mListenersDisablingEffects.keyAt(i);
1495 final ArraySet<ManagedServiceInfo> listeners =
1496 mListenersDisablingEffects.valueAt(i);
1497
1498 if (hints == 0 || (hint & hints) == hint) {
1499 removed = removed || listeners.remove(info);
1500 }
1501 }
1502
1503 return removed;
1504 }
1505
1506 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1507 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1508 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1509 }
1510
1511 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1512 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1513 }
1514
1515 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1516 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1517 }
1518 }
1519
1520 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1521 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1522 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1523 }
1524
1525 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1526 hintListeners.add(info);
1527 }
1528
1529 private int calculateHints() {
1530 int hints = 0;
1531 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1532 int hint = mListenersDisablingEffects.keyAt(i);
1533 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1534
1535 if (!serviceInfoList.isEmpty()) {
1536 hints |= hint;
1537 }
1538 }
1539
1540 return hints;
1541 }
1542
1543 private long calculateSuppressedEffects() {
1544 int hints = calculateHints();
1545 long suppressedEffects = 0;
1546
1547 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1548 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1549 }
1550
1551 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1552 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1553 }
1554
1555 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1556 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1557 }
1558
1559 return suppressedEffects;
1560 }
1561
Julia Reynolds88860ce2017-06-01 16:55:49 -04001562 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001563 private void updateInterruptionFilterLocked() {
1564 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1565 if (interruptionFilter == mInterruptionFilter) return;
1566 mInterruptionFilter = interruptionFilter;
1567 scheduleInterruptionFilterChanged(interruptionFilter);
1568 }
1569
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001570 @VisibleForTesting
1571 INotificationManager getBinderService() {
1572 return INotificationManager.Stub.asInterface(mService);
1573 }
1574
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001575 @VisibleForTesting
1576 NotificationManagerInternal getInternalService() {
1577 return mInternalService;
1578 }
1579
Adam Lesinski182f73f2013-12-05 16:48:06 -08001580 private final IBinder mService = new INotificationManager.Stub() {
1581 // Toasts
1582 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001585 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001587 if (DBG) {
1588 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1589 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001591
1592 if (pkg == null || callback == null) {
1593 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1594 return ;
1595 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001596 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001597 final boolean isPackageSuspended =
1598 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001599
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001600 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001601 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1602 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001603 Slog.e(TAG, "Suppressing toast from package " + pkg
1604 + (isPackageSuspended
1605 ? " due to package suspended by administrator."
1606 : " by user request."));
1607 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001608 }
1609
1610 synchronized (mToastQueue) {
1611 int callingPid = Binder.getCallingPid();
1612 long callingId = Binder.clearCallingIdentity();
1613 try {
1614 ToastRecord record;
Beverly4ee785b2017-08-11 12:49:56 -04001615 int index;
1616 // All packages aside from the android package can enqueue one toast at a time
1617 if (!isSystemToast) {
1618 index = indexOfToastPackageLocked(pkg);
1619 } else {
1620 index = indexOfToastLocked(pkg, callback);
1621 }
1622
1623 // If the package already has a toast, we update its toast
1624 // in the queue, we don't move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001625 if (index >= 0) {
1626 record = mToastQueue.get(index);
1627 record.update(duration);
Beverly4ee785b2017-08-11 12:49:56 -04001628 record.update(callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001629 } else {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001630 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07001631 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001632 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001633 mToastQueue.add(record);
1634 index = mToastQueue.size() - 1;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001635 }
Beverly4ee785b2017-08-11 12:49:56 -04001636 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001637 // If it's at index 0, it's the current toast. It doesn't matter if it's
1638 // new or just been updated. Call back and tell it to show itself.
1639 // If the callback fails, this will remove it from the list, so don't
1640 // assume that it's valid after this.
1641 if (index == 0) {
1642 showNextToastLocked();
1643 }
1644 } finally {
1645 Binder.restoreCallingIdentity(callingId);
1646 }
1647 }
1648 }
1649
1650 @Override
1651 public void cancelToast(String pkg, ITransientNotification callback) {
1652 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1653
1654 if (pkg == null || callback == null) {
1655 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1656 return ;
1657 }
1658
1659 synchronized (mToastQueue) {
1660 long callingId = Binder.clearCallingIdentity();
1661 try {
1662 int index = indexOfToastLocked(pkg, callback);
1663 if (index >= 0) {
1664 cancelToastLocked(index);
1665 } else {
1666 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1667 + " callback=" + callback);
1668 }
1669 } finally {
1670 Binder.restoreCallingIdentity(callingId);
1671 }
1672 }
1673 }
1674
1675 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001676 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001677 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001678 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001679 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001680 }
1681
1682 @Override
1683 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001684 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001685 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1686 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04001687 // Don't allow client applications to cancel foreground service notis or autobundled
1688 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001689 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1690 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04001691 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001692 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001693 }
1694
1695 @Override
1696 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001697 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001698
1699 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1700 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1701
1702 // Calling from user space, don't allow the canceling of actively
1703 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04001704 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001705 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001706 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001707 }
1708
1709 @Override
1710 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
John Spurlock7340fc82014-04-24 18:50:12 -04001711 checkCallerIsSystem();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001712
Chris Wrenacf424a2016-03-15 12:48:55 -04001713 mRankingHelper.setEnabled(pkg, uid, enabled);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001714 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04001715 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001716 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1717 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1718 }
Chris Wrenacf424a2016-03-15 12:48:55 -04001719 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001720 }
1721
1722 /**
1723 * Use this when you just want to know if notifications are OK for this package.
1724 */
1725 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001726 public boolean areNotificationsEnabled(String pkg) {
1727 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1728 }
1729
1730 /**
1731 * Use this when you just want to know if notifications are OK for this package.
1732 */
1733 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001734 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001735 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001736
1737 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001738 }
1739
Chris Wren54bbef42014-07-09 18:37:56 -04001740 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001741 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001742 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05001743 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001744 }
1745
1746 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05001747 public boolean canShowBadge(String pkg, int uid) {
1748 checkCallerIsSystem();
1749 return mRankingHelper.canShowBadge(pkg, uid);
1750 }
1751
1752 @Override
1753 public void setShowBadge(String pkg, int uid, boolean showBadge) {
1754 checkCallerIsSystem();
1755 mRankingHelper.setShowBadge(pkg, uid, showBadge);
1756 savePolicyFile();
1757 }
1758
1759 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05001760 public void createNotificationChannelGroups(String pkg,
1761 ParceledListSlice channelGroupList) throws RemoteException {
1762 checkCallerIsSystemOrSameApp(pkg);
1763 List<NotificationChannelGroup> groups = channelGroupList.getList();
1764 final int groupSize = groups.size();
1765 for (int i = 0; i < groupSize; i++) {
1766 final NotificationChannelGroup group = groups.get(i);
1767 Preconditions.checkNotNull(group, "group in list is null");
1768 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1769 true /* fromTargetApp */);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001770 mListeners.notifyNotificationChannelGroupChanged(pkg,
1771 UserHandle.of(UserHandle.getCallingUserId()), group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001772 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Julia Reynolds59e152e2017-01-25 17:42:53 -05001773 }
1774 savePolicyFile();
1775 }
1776
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001777 private void createNotificationChannelsImpl(String pkg, int uid,
1778 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001779 List<NotificationChannel> channels = channelsList.getList();
1780 final int channelsSize = channels.size();
1781 for (int i = 0; i < channelsSize; i++) {
1782 final NotificationChannel channel = channels.get(i);
1783 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001784 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001785 true /* fromTargetApp */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001786 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001787 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001788 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1789 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001790 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001791 savePolicyFile();
1792 }
1793
1794 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001795 public void createNotificationChannels(String pkg,
1796 ParceledListSlice channelsList) throws RemoteException {
1797 checkCallerIsSystemOrSameApp(pkg);
1798 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1799 }
1800
1801 @Override
1802 public void createNotificationChannelsForPackage(String pkg, int uid,
1803 ParceledListSlice channelsList) throws RemoteException {
1804 checkCallerIsSystem();
1805 createNotificationChannelsImpl(pkg, uid, channelsList);
1806 }
1807
1808 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001809 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001810 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001811 return mRankingHelper.getNotificationChannel(
1812 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001813 }
1814
1815 @Override
1816 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001817 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001818 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04001819 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001820 }
1821
1822 @Override
1823 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001824 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001825 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001826 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1827 throw new IllegalArgumentException("Cannot delete default channel");
1828 }
1829 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001830 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1831 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1832 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001833 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001834 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1835 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001836 savePolicyFile();
1837 }
1838
1839 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04001840 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1841 String pkg) {
1842 checkCallerIsSystemOrSameApp(pkg);
1843 return new ParceledListSlice<>(new ArrayList(
1844 mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1845 }
1846
1847 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001848 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04001849 checkCallerIsSystemOrSameApp(pkg);
1850
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001851 final int callingUid = Binder.getCallingUid();
1852 NotificationChannelGroup groupToDelete =
1853 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1854 if (groupToDelete != null) {
1855 List<NotificationChannel> deletedChannels =
1856 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1857 for (int i = 0; i < deletedChannels.size(); i++) {
1858 final NotificationChannel deletedChannel = deletedChannels.get(i);
1859 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1860 true,
1861 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1862 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001863 mListeners.notifyNotificationChannelChanged(pkg,
1864 UserHandle.getUserHandleForUid(callingUid),
1865 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001866 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1867 }
1868 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001869 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1870 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001871 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04001872 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04001873 }
1874
1875 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001876 public void updateNotificationChannelForPackage(String pkg, int uid,
1877 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001878 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05001879 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001880 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001881 }
1882
1883 @Override
1884 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001885 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05001886 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001887 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001888 }
1889
1890 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05001891 public int getNumNotificationChannelsForPackage(String pkg, int uid,
1892 boolean includeDeleted) {
1893 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1894 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1895 .getList().size();
1896 }
1897
1898 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04001899 public boolean onlyHasDefaultChannel(String pkg, int uid) {
1900 enforceSystemOrSystemUI("onlyHasDefaultChannel");
1901 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1902 }
1903
1904 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04001905 public int getDeletedChannelCount(String pkg, int uid) {
1906 enforceSystemOrSystemUI("getDeletedChannelCount");
1907 return mRankingHelper.getDeletedChannelCount(pkg, uid);
1908 }
1909
1910 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05001911 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1912 String pkg, int uid, boolean includeDeleted) {
1913 checkCallerIsSystem();
1914 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1915 }
1916
1917 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05001918 public NotificationChannelGroup getNotificationChannelGroupForPackage(
1919 String groupId, String pkg, int uid) {
1920 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1921 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1922 }
1923
1924 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001925 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1926 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001927 return mRankingHelper.getNotificationChannels(
1928 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001929 }
1930
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001931 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05001932 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001933 checkCallerIsSystem();
1934
1935 // Cancel posted notifications
1936 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1937 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1938
Julia Reynoldsb852e562017-06-06 16:14:18 -04001939 final String[] packages = new String[] {packageName};
1940 final int[] uids = new int[] {uid};
1941
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001942 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04001943 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001944 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001945
1946 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04001947 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001948
1949 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05001950 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04001951 mRankingHelper.onPackagesChanged(
1952 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05001953 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001954
1955 savePolicyFile();
1956 }
1957
1958
Adam Lesinski182f73f2013-12-05 16:48:06 -08001959 /**
1960 * System-only API for getting a list of current (i.e. not cleared) notifications.
1961 *
1962 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04001963 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001964 */
1965 @Override
1966 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1967 // enforce() will ensure the calling uid has the correct permission
1968 getContext().enforceCallingOrSelfPermission(
1969 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1970 "NotificationManagerService.getActiveNotifications");
1971
1972 StatusBarNotification[] tmp = null;
1973 int uid = Binder.getCallingUid();
1974
1975 // noteOp will check to make sure the callingPkg matches the uid
1976 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1977 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001978 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001979 tmp = new StatusBarNotification[mNotificationList.size()];
1980 final int N = mNotificationList.size();
1981 for (int i=0; i<N; i++) {
1982 tmp[i] = mNotificationList.get(i).sbn;
1983 }
1984 }
1985 }
1986 return tmp;
1987 }
1988
1989 /**
Dan Sandler994349c2015-04-15 11:02:54 -04001990 * Public API for getting a list of current notifications for the calling package/uid.
1991 *
Julia Reynolds573c6532017-01-24 17:44:38 -05001992 * Note that since notification posting is done asynchronously, this will not return
1993 * notifications that are in the process of being posted.
1994 *
Dan Sandler994349c2015-04-15 11:02:54 -04001995 * @returns A list of all the package's notifications, in natural order.
1996 */
1997 @Override
1998 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
1999 int incomingUserId) {
2000 checkCallerIsSystemOrSameApp(pkg);
2001 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2002 Binder.getCallingUid(), incomingUserId, true, false,
2003 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002004 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002005 final ArrayMap<String, StatusBarNotification> map
2006 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002007 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002008 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002009 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2010 mNotificationList.get(i).sbn);
2011 if (sbn != null) {
2012 map.put(sbn.getKey(), sbn);
2013 }
2014 }
2015 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2016 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2017 if (sbn != null) {
2018 map.put(sbn.getKey(), sbn);
2019 }
2020 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002021 final int M = mEnqueuedNotifications.size();
2022 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002023 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2024 mEnqueuedNotifications.get(i).sbn);
2025 if (sbn != null) {
2026 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002027 }
2028 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002029 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2030 list.addAll(map.values());
2031 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002032 }
Dan Sandler994349c2015-04-15 11:02:54 -04002033 }
2034
Chris Wren6676dab2016-12-21 18:26:27 -05002035 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2036 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002037 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002038 // We could pass back a cloneLight() but clients might get confused and
2039 // try to send this thing back to notify() again, which would not work
2040 // very well.
2041 return new StatusBarNotification(
2042 sbn.getPackageName(),
2043 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002044 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2045 sbn.getNotification().clone(),
2046 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2047 }
2048 return null;
2049 }
2050
Dan Sandler994349c2015-04-15 11:02:54 -04002051 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002052 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2053 *
2054 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2055 */
2056 @Override
2057 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2058 // enforce() will ensure the calling uid has the correct permission
2059 getContext().enforceCallingOrSelfPermission(
2060 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2061 "NotificationManagerService.getHistoricalNotifications");
2062
2063 StatusBarNotification[] tmp = null;
2064 int uid = Binder.getCallingUid();
2065
2066 // noteOp will check to make sure the callingPkg matches the uid
2067 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2068 == AppOpsManager.MODE_ALLOWED) {
2069 synchronized (mArchive) {
2070 tmp = mArchive.getArray(count);
2071 }
2072 }
2073 return tmp;
2074 }
2075
2076 /**
2077 * Register a listener binder directly with the notification manager.
2078 *
2079 * Only works with system callers. Apps should extend
2080 * {@link android.service.notification.NotificationListenerService}.
2081 */
2082 @Override
2083 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002084 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002085 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002086 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002087 }
2088
2089 /**
2090 * Remove a listener binder directly
2091 */
2092 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002093 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002094 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002095 }
2096
2097 /**
2098 * Allow an INotificationListener to simulate a "clear all" operation.
2099 *
2100 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2101 *
2102 * @param token The binder for the listener, to check that the caller is allowed
2103 */
2104 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002105 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002106 final int callingUid = Binder.getCallingUid();
2107 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002108 long identity = Binder.clearCallingIdentity();
2109 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002110 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002111 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
John Spurlocka4294292014-03-24 18:02:32 -04002112 if (keys != null) {
2113 final int N = keys.length;
2114 for (int i = 0; i < N; i++) {
2115 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002116 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002117 final int userId = r.sbn.getUserId();
2118 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002119 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002120 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002121 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002122 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002123 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2124 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2125 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002126 }
2127 } else {
2128 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002129 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002130 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002131 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002132 } finally {
2133 Binder.restoreCallingIdentity(identity);
2134 }
2135 }
2136
Chris Wrenab41eec2016-01-04 18:01:27 -05002137 /**
2138 * Handle request from an approved listener to re-enable itself.
2139 *
2140 * @param component The componenet to be re-enabled, caller must match package.
2141 */
2142 @Override
2143 public void requestBindListener(ComponentName component) {
2144 checkCallerIsSystemOrSameApp(component.getPackageName());
2145 long identity = Binder.clearCallingIdentity();
2146 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002147 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002148 mAssistants.isComponentEnabledForCurrentProfiles(component)
2149 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002150 : mListeners;
2151 manager.setComponentState(component, true);
2152 } finally {
2153 Binder.restoreCallingIdentity(identity);
2154 }
2155 }
2156
2157 @Override
2158 public void requestUnbindListener(INotificationListener token) {
2159 long identity = Binder.clearCallingIdentity();
2160 try {
2161 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002162 synchronized (mNotificationLock) {
2163 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2164 info.getOwner().setComponentState(info.component, false);
2165 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002166 } finally {
2167 Binder.restoreCallingIdentity(identity);
2168 }
2169 }
2170
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002171 @Override
2172 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002173 long identity = Binder.clearCallingIdentity();
2174 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002175 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002176 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2177 if (keys != null) {
2178 final int N = keys.length;
2179 for (int i = 0; i < N; i++) {
2180 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2181 if (r == null) continue;
2182 final int userId = r.sbn.getUserId();
2183 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2184 !mUserProfiles.isCurrentProfile(userId)) {
2185 throw new SecurityException("Disallowed call from listener: "
2186 + info.service);
2187 }
2188 if (!r.isSeen()) {
2189 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2190 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002191 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002192 : userId,
Adam Lesinskic8e87292015-06-10 15:33:45 -07002193 UsageEvents.Event.USER_INTERACTION);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002194 r.setSeen();
2195 }
2196 }
2197 }
2198 }
2199 } finally {
2200 Binder.restoreCallingIdentity(identity);
2201 }
2202 }
2203
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002204 /**
2205 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2206 *
2207 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2208 *
Julia Reynolds79672302017-01-12 08:30:16 -05002209 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002210 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002211 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002212 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002213 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002214 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2215 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2216 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002217 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002218 }
2219
Adam Lesinski182f73f2013-12-05 16:48:06 -08002220 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002221 * Allow an INotificationListener to snooze a single notification until a context.
2222 *
2223 * @param token The binder for the listener, to check that the caller is allowed
2224 */
2225 @Override
2226 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2227 String key, String snoozeCriterionId) {
2228 long identity = Binder.clearCallingIdentity();
2229 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002230 synchronized (mNotificationLock) {
2231 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2232 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2233 }
Julia Reynolds79672302017-01-12 08:30:16 -05002234 } finally {
2235 Binder.restoreCallingIdentity(identity);
2236 }
2237 }
2238
2239 /**
2240 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002241 *
2242 * @param token The binder for the listener, to check that the caller is allowed
2243 */
2244 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002245 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002246 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002247 long identity = Binder.clearCallingIdentity();
2248 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002249 synchronized (mNotificationLock) {
2250 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2251 snoozeNotificationInt(key, duration, null, info);
2252 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002253 } finally {
2254 Binder.restoreCallingIdentity(identity);
2255 }
2256 }
2257
2258 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002259 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002260 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002261 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002262 */
2263 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002264 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002265 long identity = Binder.clearCallingIdentity();
2266 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002267 synchronized (mNotificationLock) {
2268 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002269 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002270 unsnoozeNotificationInt(key, info);
2271 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002272 } finally {
2273 Binder.restoreCallingIdentity(identity);
2274 }
2275 }
2276
2277 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002278 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2279 *
2280 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2281 *
2282 * @param token The binder for the listener, to check that the caller is allowed
2283 */
2284 @Override
2285 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2286 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002287 final int callingUid = Binder.getCallingUid();
2288 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002289 long identity = Binder.clearCallingIdentity();
2290 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002291 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002292 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002293 if (info.supportsProfiles()) {
2294 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2295 + "from " + info.component
2296 + " use cancelNotification(key) instead.");
2297 } else {
2298 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2299 pkg, tag, id, info.userid);
2300 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002301 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002302 } finally {
2303 Binder.restoreCallingIdentity(identity);
2304 }
2305 }
2306
2307 /**
2308 * Allow an INotificationListener to request the list of outstanding notifications seen by
2309 * the current user. Useful when starting up, after which point the listener callbacks
2310 * should be used.
2311 *
2312 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002313 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002314 * @returns The return value will contain the notifications specified in keys, in that
2315 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002316 */
2317 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002318 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002319 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002320 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002321 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002322 final boolean getKeys = keys != null;
2323 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002324 final ArrayList<StatusBarNotification> list
2325 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002326 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002327 final NotificationRecord r = getKeys
2328 ? mNotificationsByKey.get(keys[i])
2329 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002330 if (r == null) continue;
2331 StatusBarNotification sbn = r.sbn;
2332 if (!isVisibleToListener(sbn, info)) continue;
2333 StatusBarNotification sbnToSend =
2334 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2335 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002336 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002337 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002338 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002339 }
2340
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002341 /**
2342 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2343 * seen by the current user. Useful when starting up, after which point the listener
2344 * callbacks should be used.
2345 *
2346 * @param token The binder for the listener, to check that the caller is allowed
2347 * @returns The return value will contain the notifications specified in keys, in that
2348 * order, or if keys is null, all the notifications, in natural order.
2349 */
2350 @Override
2351 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2352 INotificationListener token, int trim) {
2353 synchronized (mNotificationLock) {
2354 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2355 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2356 final int N = snoozedRecords.size();
2357 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2358 for (int i=0; i < N; i++) {
2359 final NotificationRecord r = snoozedRecords.get(i);
2360 if (r == null) continue;
2361 StatusBarNotification sbn = r.sbn;
2362 if (!isVisibleToListener(sbn, info)) continue;
2363 StatusBarNotification sbnToSend =
2364 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2365 list.add(sbnToSend);
2366 }
2367 return new ParceledListSlice<>(list);
2368 }
2369 }
2370
Adam Lesinski182f73f2013-12-05 16:48:06 -08002371 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002372 public void requestHintsFromListener(INotificationListener token, int hints) {
2373 final long identity = Binder.clearCallingIdentity();
2374 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002375 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002376 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002377 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2378 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2379 | HINT_HOST_DISABLE_CALL_EFFECTS;
2380 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002381 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002382 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002383 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002384 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002385 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002386 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002387 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002388 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002389 } finally {
2390 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002391 }
2392 }
2393
2394 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002395 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002396 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002397 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002398 }
2399 }
2400
2401 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002402 public void requestInterruptionFilterFromListener(INotificationListener token,
2403 int interruptionFilter) throws RemoteException {
2404 final long identity = Binder.clearCallingIdentity();
2405 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002406 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002407 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2408 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002409 updateInterruptionFilterLocked();
2410 }
2411 } finally {
2412 Binder.restoreCallingIdentity(identity);
2413 }
2414 }
2415
2416 @Override
2417 public int getInterruptionFilterFromListener(INotificationListener token)
2418 throws RemoteException {
2419 synchronized (mNotificationLight) {
2420 return mInterruptionFilter;
2421 }
2422 }
2423
2424 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002425 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2426 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002427 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002428 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2429 if (info == null) return;
2430 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2431 }
2432 }
2433
2434 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002435 public int getZenMode() {
2436 return mZenModeHelper.getZenMode();
2437 }
2438
2439 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002440 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002441 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002442 return mZenModeHelper.getConfig();
2443 }
2444
2445 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002446 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002447 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002448 final long identity = Binder.clearCallingIdentity();
2449 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002450 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002451 } finally {
2452 Binder.restoreCallingIdentity(identity);
2453 }
2454 }
2455
2456 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002457 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002458 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002459 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002460 }
2461
2462 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002463 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2464 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002465 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002466 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002467 }
2468
2469 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002470 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002471 throws RemoteException {
2472 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2473 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2474 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2475 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002476 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002477
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002478 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2479 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002480 }
2481
2482 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002483 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002484 throws RemoteException {
2485 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2486 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2487 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2488 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2489 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002490
Julia Reynolds361e82d32016-02-26 18:19:49 -05002491 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002492 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002493 }
2494
2495 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002496 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2497 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002498 // Verify that they can modify zen rules.
2499 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2500
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002501 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002502 }
2503
2504 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05002505 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2506 Preconditions.checkNotNull(packageName, "Package name is null");
2507 enforceSystemOrSystemUI("removeAutomaticZenRules");
2508
2509 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2510 }
2511
2512 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05002513 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2514 Preconditions.checkNotNull(owner, "Owner is null");
2515 enforceSystemOrSystemUI("getRuleInstanceCount");
2516
2517 return mZenModeHelper.getCurrentInstanceCount(owner);
2518 }
2519
2520 @Override
John Spurlock80774932015-05-07 17:38:50 -04002521 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2522 enforcePolicyAccess(pkg, "setInterruptionFilter");
2523 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2524 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2525 final long identity = Binder.clearCallingIdentity();
2526 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002527 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04002528 } finally {
2529 Binder.restoreCallingIdentity(identity);
2530 }
2531 }
2532
2533 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04002534 public void notifyConditions(final String pkg, IConditionProvider provider,
2535 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04002536 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2537 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04002538 mHandler.post(new Runnable() {
2539 @Override
2540 public void run() {
2541 mConditionProviders.notifyConditions(pkg, info, conditions);
2542 }
2543 });
John Spurlocke77bb362014-04-26 10:24:59 -04002544 }
2545
Julia Reynolds38e6ca42016-08-08 08:38:09 -04002546 @Override
2547 public void requestUnbindProvider(IConditionProvider provider) {
2548 long identity = Binder.clearCallingIdentity();
2549 try {
2550 // allow bound services to disable themselves
2551 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2552 info.getOwner().setComponentState(info.component, false);
2553 } finally {
2554 Binder.restoreCallingIdentity(identity);
2555 }
2556 }
2557
2558 @Override
2559 public void requestBindProvider(ComponentName component) {
2560 checkCallerIsSystemOrSameApp(component.getPackageName());
2561 long identity = Binder.clearCallingIdentity();
2562 try {
2563 mConditionProviders.setComponentState(component, true);
2564 } finally {
2565 Binder.restoreCallingIdentity(identity);
2566 }
2567 }
2568
John Spurlocke77bb362014-04-26 10:24:59 -04002569 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002570 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04002571 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2572 message);
John Spurlock7340fc82014-04-24 18:50:12 -04002573 }
2574
Julia Reynolds48034f82016-03-09 10:15:16 -05002575 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2576 try {
2577 checkCallerIsSystemOrSameApp(pkg);
2578 } catch (SecurityException e) {
2579 getContext().enforceCallingPermission(
2580 android.Manifest.permission.STATUS_BAR_SERVICE,
2581 message);
2582 }
2583 }
2584
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002585 private void enforcePolicyAccess(int uid, String method) {
2586 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2587 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2588 return;
2589 }
2590 boolean accessAllowed = false;
2591 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2592 final int packageCount = packages.length;
2593 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002594 if (mConditionProviders.isPackageOrComponentAllowed(
2595 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002596 accessAllowed = true;
2597 }
2598 }
2599 if (!accessAllowed) {
2600 Slog.w(TAG, "Notification policy access denied calling " + method);
2601 throw new SecurityException("Notification policy access denied");
2602 }
2603 }
2604
John Spurlock80774932015-05-07 17:38:50 -04002605 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04002606 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2607 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2608 return;
2609 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04002610 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002611 if (!checkPolicyAccess(pkg)) {
2612 Slog.w(TAG, "Notification policy access denied calling " + method);
2613 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04002614 }
2615 }
2616
John Spurlock80774932015-05-07 17:38:50 -04002617 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002618 return mConditionProviders.isPackageOrComponentAllowed(
2619 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04002620 }
2621
2622 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04002623 try {
2624 int uid = getContext().getPackageManager().getPackageUidAsUser(
2625 pkg, UserHandle.getCallingUserId());
2626 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2627 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2628 -1, true)) {
2629 return true;
2630 }
2631 } catch (NameNotFoundException e) {
2632 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002633 }
John Spurlock80774932015-05-07 17:38:50 -04002634 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002635 }
2636
John Spurlock7340fc82014-04-24 18:50:12 -04002637 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002638 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002639 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04002640 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2641 if (filter != null && filter.stats) {
2642 dumpJson(pw, filter);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05002643 } else if (filter != null && filter.proto) {
2644 dumpProto(fd, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04002645 } else {
2646 dumpImpl(pw, filter);
2647 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002648 }
John Spurlockb4782522014-08-22 14:54:46 -04002649
2650 @Override
2651 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07002652 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04002653 }
John Spurlock2b122f42014-08-27 16:29:47 -04002654
2655 @Override
2656 public boolean matchesCallFilter(Bundle extras) {
2657 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02002658 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002659 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02002660 extras,
2661 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2662 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2663 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04002664 }
John Spurlock530052a2014-11-30 16:26:19 -05002665
2666 @Override
2667 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002668 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04002669 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05002670 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002671
Christopher Tatef9767d62015-04-08 14:35:43 -07002672 // Backup/restore interface
2673 @Override
2674 public byte[] getBackupPayload(int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002675 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002676 //TODO: http://b/22388012
2677 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002678 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2679 return null;
2680 }
songjinshi9bf22712017-02-04 10:47:45 +08002681 synchronized(mPolicyFile) {
2682 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2683 try {
2684 writePolicyXml(baos, true /*forBackup*/);
2685 return baos.toByteArray();
2686 } catch (IOException e) {
2687 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2688 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002689 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002690 return null;
2691 }
2692
2693 @Override
2694 public void applyRestore(byte[] payload, int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002695 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2696 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2697 if (payload == null) {
2698 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2699 return;
2700 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002701 //TODO: http://b/22388012
2702 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002703 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2704 return;
2705 }
songjinshi9bf22712017-02-04 10:47:45 +08002706 synchronized(mPolicyFile) {
2707 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2708 try {
2709 readPolicyXml(bais, true /*forRestore*/);
2710 savePolicyFile();
2711 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2712 Slog.w(TAG, "applyRestore: error reading payload", e);
2713 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002714 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002715 }
2716
John Spurlock1fc476d2015-04-14 16:05:20 -04002717 @Override
John Spurlock80774932015-05-07 17:38:50 -04002718 public boolean isNotificationPolicyAccessGranted(String pkg) {
2719 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002720 }
2721
2722 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05002723 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2724 enforceSystemOrSystemUIOrSamePackage(pkg,
2725 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002726 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002727 }
2728
2729 @Override
John Spurlock80774932015-05-07 17:38:50 -04002730 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2731 throws RemoteException {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002732 checkCallerIsSystemOrShell();
Julia Reynolds68263d12017-06-21 14:21:19 -04002733 if (!mActivityManager.isLowRamDevice()) {
2734 mConditionProviders.setPackageOrComponentEnabled(
2735 pkg, getCallingUserHandle().getIdentifier(), true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002736
Julia Reynolds68263d12017-06-21 14:21:19 -04002737 getContext().sendBroadcastAsUser(new Intent(
2738 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2739 .setPackage(pkg)
2740 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2741 getCallingUserHandle(), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002742
Julia Reynolds68263d12017-06-21 14:21:19 -04002743 savePolicyFile();
2744 }
John Spurlock80774932015-05-07 17:38:50 -04002745 }
2746
2747 @Override
2748 public Policy getNotificationPolicy(String pkg) {
2749 enforcePolicyAccess(pkg, "getNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002750 final long identity = Binder.clearCallingIdentity();
2751 try {
2752 return mZenModeHelper.getNotificationPolicy();
2753 } finally {
2754 Binder.restoreCallingIdentity(identity);
2755 }
2756 }
2757
2758 @Override
John Spurlock80774932015-05-07 17:38:50 -04002759 public void setNotificationPolicy(String pkg, Policy policy) {
2760 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002761 final long identity = Binder.clearCallingIdentity();
2762 try {
2763 mZenModeHelper.setNotificationPolicy(policy);
2764 } finally {
2765 Binder.restoreCallingIdentity(identity);
2766 }
2767 }
Chris Wren51017d02015-12-15 15:34:46 -05002768
2769 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04002770 public List<String> getEnabledNotificationListenerPackages() {
2771 checkCallerIsSystem();
2772 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
2773 }
2774
2775 @Override
2776 public List<ComponentName> getEnabledNotificationListeners(int userId) {
2777 checkCallerIsSystem();
2778 return mListeners.getAllowedComponents(userId);
2779 }
2780
2781 @Override
2782 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
2783 Preconditions.checkNotNull(listener);
2784 checkCallerIsSystemOrSameApp(listener.getPackageName());
2785 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2786 getCallingUserHandle().getIdentifier());
2787 }
2788
2789 @Override
2790 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
2791 int userId) {
2792 Preconditions.checkNotNull(listener);
2793 checkCallerIsSystem();
2794 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2795 userId);
2796 }
2797
2798 @Override
2799 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
2800 Preconditions.checkNotNull(assistant);
2801 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002802 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04002803 getCallingUserHandle().getIdentifier());
2804 }
2805
2806 @Override
2807 public void setNotificationListenerAccessGranted(ComponentName listener,
2808 boolean granted) throws RemoteException {
2809 setNotificationListenerAccessGrantedForUser(
2810 listener, getCallingUserHandle().getIdentifier(), granted);
2811 }
2812
2813 @Override
2814 public void setNotificationAssistantAccessGranted(ComponentName assistant,
2815 boolean granted) throws RemoteException {
2816 setNotificationAssistantAccessGrantedForUser(
2817 assistant, getCallingUserHandle().getIdentifier(), granted);
2818 }
2819
2820 @Override
2821 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
2822 boolean granted) throws RemoteException {
2823 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04002824 checkCallerIsSystemOrShell();
Julia Reynolds68263d12017-06-21 14:21:19 -04002825 if (!mActivityManager.isLowRamDevice()) {
2826 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
2827 userId, false, granted);
2828 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
2829 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002830
Julia Reynolds68263d12017-06-21 14:21:19 -04002831 getContext().sendBroadcastAsUser(new Intent(
2832 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2833 .setPackage(listener.getPackageName())
2834 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2835 getCallingUserHandle(), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002836
Julia Reynolds68263d12017-06-21 14:21:19 -04002837 savePolicyFile();
2838 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04002839 }
2840
2841 @Override
2842 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
2843 int userId, boolean granted) throws RemoteException {
2844 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04002845 checkCallerIsSystemOrShell();
Julia Reynolds68263d12017-06-21 14:21:19 -04002846 if (!mActivityManager.isLowRamDevice()) {
2847 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
2848 userId, false, granted);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002849 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
Julia Reynolds68263d12017-06-21 14:21:19 -04002850 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002851
Julia Reynolds68263d12017-06-21 14:21:19 -04002852 getContext().sendBroadcastAsUser(new Intent(
2853 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2854 .setPackage(assistant.getPackageName())
2855 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2856 getCallingUserHandle(), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002857
Julia Reynolds68263d12017-06-21 14:21:19 -04002858 savePolicyFile();
2859 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04002860 }
2861
2862 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002863 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2864 Adjustment adjustment) throws RemoteException {
2865 final long identity = Binder.clearCallingIdentity();
2866 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002867 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002868 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002869 int N = mEnqueuedNotifications.size();
2870 for (int i = 0; i < N; i++) {
2871 final NotificationRecord n = mEnqueuedNotifications.get(i);
2872 if (Objects.equals(adjustment.getKey(), n.getKey())
2873 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2874 applyAdjustment(n, adjustment);
2875 break;
2876 }
2877 }
2878 }
2879 } finally {
2880 Binder.restoreCallingIdentity(identity);
2881 }
2882 }
2883
2884 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05002885 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04002886 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05002887 final long identity = Binder.clearCallingIdentity();
2888 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002889 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002890 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002891 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2892 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05002893 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002894 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04002895 } finally {
2896 Binder.restoreCallingIdentity(identity);
2897 }
2898 }
2899
2900 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05002901 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04002902 List<Adjustment> adjustments) throws RemoteException {
2903
2904 final long identity = Binder.clearCallingIdentity();
2905 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002906 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002907 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002908 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002909 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2910 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002911 }
2912 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002913 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05002914 } finally {
2915 Binder.restoreCallingIdentity(identity);
2916 }
2917 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002918
2919 @Override
2920 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002921 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002922 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002923 Preconditions.checkNotNull(pkg);
2924 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002925
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002926 verifyPrivilegedListener(token, user);
2927 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002928 }
2929
2930 @Override
2931 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002932 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2933 Preconditions.checkNotNull(pkg);
2934 Preconditions.checkNotNull(user);
2935 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002936
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002937 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2938 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002939 }
2940
2941 @Override
2942 public ParceledListSlice<NotificationChannelGroup>
2943 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002944 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2945 Preconditions.checkNotNull(pkg);
2946 Preconditions.checkNotNull(user);
2947 verifyPrivilegedListener(token, user);
2948
2949 List<NotificationChannelGroup> groups = new ArrayList<>();
2950 groups.addAll(mRankingHelper.getNotificationChannelGroups(
2951 pkg, getUidForPackageAndUser(pkg, user)));
2952 return new ParceledListSlice<>(groups);
2953 }
2954
2955 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002956 ManagedServiceInfo info;
2957 synchronized (mNotificationLock) {
2958 info = mListeners.checkServiceTokenLocked(token);
2959 }
Julia Reynoldsda781472017-04-12 09:41:16 -04002960 if (!hasCompanionDevice(info)) {
2961 throw new SecurityException(info + " does not have access");
2962 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002963 if (!info.enabledAndUserMatches(user.getIdentifier())) {
2964 throw new SecurityException(info + " does not have access");
2965 }
2966 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002967
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002968 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
2969 int uid = 0;
2970 long identity = Binder.clearCallingIdentity();
2971 try {
2972 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
2973 } finally {
2974 Binder.restoreCallingIdentity(identity);
2975 }
2976 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002977 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04002978
2979 @Override
2980 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2981 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
2982 throws RemoteException {
2983 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
2984 }
John Spurlock1fc476d2015-04-14 16:05:20 -04002985 };
John Spurlocka4294292014-03-24 18:02:32 -04002986
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002987 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
2988 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002989 return;
2990 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002991 if (adjustment.getSignals() != null) {
2992 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002993 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002994 }
2995 }
2996
Julia Reynolds88860ce2017-06-01 16:55:49 -04002997 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002998 void addAutogroupKeyLocked(String key) {
2999 NotificationRecord r = mNotificationsByKey.get(key);
3000 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003001 return;
3002 }
Julia Reynolds51710712017-07-19 13:48:07 -04003003 if (r.sbn.getOverrideGroupKey() == null) {
3004 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3005 EventLogTags.writeNotificationAutogrouped(key);
3006 mRankingHandler.requestSort();
3007 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003008 }
3009
Julia Reynolds88860ce2017-06-01 16:55:49 -04003010 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003011 void removeAutogroupKeyLocked(String key) {
3012 NotificationRecord r = mNotificationsByKey.get(key);
3013 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003014 return;
3015 }
Julia Reynolds51710712017-07-19 13:48:07 -04003016 if (r.sbn.getOverrideGroupKey() != null) {
3017 addAutoGroupAdjustment(r, null);
3018 EventLogTags.writeNotificationUnautogrouped(key);
3019 mRankingHandler.requestSort();
3020 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003021 }
3022
3023 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3024 Bundle signals = new Bundle();
3025 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3026 Adjustment adjustment =
3027 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3028 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003029 }
3030
3031 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003032 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003033 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3034 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3035 if (summaries != null && summaries.containsKey(pkg)) {
3036 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003037 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003038 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003039 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003040 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003041 }
3042 }
3043 }
3044
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003045 @GuardedBy("mNotificationLock")
3046 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3047 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3048 return summaries != null && summaries.containsKey(sbn.getPackageName());
3049 }
3050
Julia Reynoldse46bb372016-03-17 11:05:58 -04003051 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003052 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3053 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003054 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003055 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3056 if (notificationRecord == null) {
3057 // The notification could have been cancelled again already. A successive
3058 // adjustment will post a summary if needed.
3059 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003060 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003061 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3062 userId = adjustedSbn.getUser().getIdentifier();
3063 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3064 if (summaries == null) {
3065 summaries = new ArrayMap<>();
3066 }
3067 mAutobundledSummaries.put(userId, summaries);
3068 if (!summaries.containsKey(pkg)) {
3069 // Add summary
3070 final ApplicationInfo appInfo =
3071 adjustedSbn.getNotification().extras.getParcelable(
3072 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3073 final Bundle extras = new Bundle();
3074 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003075 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003076 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003077 new Notification.Builder(getContext(), channelId)
3078 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003079 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003080 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003081 .setGroup(GroupHelper.AUTOGROUP_KEY)
3082 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3083 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3084 .setColor(adjustedSbn.getNotification().color)
3085 .setLocalOnly(true)
3086 .build();
3087 summaryNotification.extras.putAll(extras);
3088 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3089 if (appIntent != null) {
3090 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3091 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3092 }
3093 final StatusBarNotification summarySbn =
3094 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003095 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003096 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003097 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3098 adjustedSbn.getInitialPid(), summaryNotification,
3099 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3100 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003101 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003102 notificationRecord.getChannel());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003103 summaries.put(pkg, summarySbn.getKey());
3104 }
3105 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003106 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003107 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003108 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003109 }
3110 }
3111
John Spurlock32fe4c62014-10-02 12:16:02 -04003112 private String disableNotificationEffects(NotificationRecord record) {
3113 if (mDisableNotificationEffects) {
3114 return "booleanState";
3115 }
3116 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3117 return "listenerHints";
3118 }
3119 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3120 return "callState";
3121 }
3122 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003123 };
3124
3125 private void dumpJson(PrintWriter pw, DumpFilter filter) {
3126 JSONObject dump = new JSONObject();
3127 try {
3128 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003129 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3130 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003131 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003132 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003133 } catch (JSONException e) {
3134 e.printStackTrace();
3135 }
3136 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003137 }
3138
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003139 private void dumpProto(FileDescriptor fd, DumpFilter filter) {
3140 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3141 synchronized (mNotificationLock) {
3142 long records = proto.start(NotificationServiceDumpProto.RECORDS);
3143 int N = mNotificationList.size();
3144 if (N > 0) {
3145 for (int i = 0; i < N; i++) {
3146 final NotificationRecord nr = mNotificationList.get(i);
3147 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3148 nr.dump(proto, filter.redact);
3149 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
3150 }
3151 }
3152 N = mEnqueuedNotifications.size();
3153 if (N > 0) {
3154 for (int i = 0; i < N; i++) {
3155 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3156 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3157 nr.dump(proto, filter.redact);
3158 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
3159 }
3160 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003161 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3162 N = snoozed.size();
3163 if (N > 0) {
3164 for (int i = 0; i < N; i++) {
3165 final NotificationRecord nr = snoozed.get(i);
3166 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3167 nr.dump(proto, filter.redact);
3168 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
3169 }
3170 }
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003171 proto.end(records);
3172 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003173
3174 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3175 mZenModeHelper.dump(proto);
3176 for (ComponentName suppressor : mEffectsSuppressors) {
3177 proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
3178 }
3179 proto.end(zenLog);
3180
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003181 proto.flush();
3182 }
3183
John Spurlock25e2d242014-06-27 13:58:23 -04003184 void dumpImpl(PrintWriter pw, DumpFilter filter) {
3185 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003186 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003187 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003188 }
3189 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003190 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003191 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003192
John Spurlock50806fc2014-07-15 10:22:02 -04003193 if (!zenOnly) {
3194 synchronized (mToastQueue) {
3195 N = mToastQueue.size();
3196 if (N > 0) {
3197 pw.println(" Toast Queue:");
3198 for (int i=0; i<N; i++) {
3199 mToastQueue.get(i).dump(pw, " ", filter);
3200 }
3201 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003202 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003203 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003204 }
3205
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003206 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003207 if (!zenOnly) {
3208 N = mNotificationList.size();
John Spurlock25e2d242014-06-27 13:58:23 -04003209 if (N > 0) {
John Spurlock50806fc2014-07-15 10:22:02 -04003210 pw.println(" Notification List:");
John Spurlock25e2d242014-06-27 13:58:23 -04003211 for (int i=0; i<N; i++) {
John Spurlock50806fc2014-07-15 10:22:02 -04003212 final NotificationRecord nr = mNotificationList.get(i);
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003213 if (filter.filtered && !filter.matches(nr.sbn)) continue;
Dan Sandlera1770312015-07-10 13:59:29 -04003214 nr.dump(pw, " ", getContext(), filter.redact);
John Spurlock25e2d242014-06-27 13:58:23 -04003215 }
3216 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003217 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003218
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003219 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003220 N = mLights.size();
3221 if (N > 0) {
3222 pw.println(" Lights List:");
3223 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003224 if (i == N - 1) {
3225 pw.print(" > ");
3226 } else {
3227 pw.print(" ");
3228 }
3229 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003230 }
3231 pw.println(" ");
3232 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003233 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3234 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003235 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3236 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003237 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003238 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003239 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003240 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003241 }
3242 pw.println(" mArchive=" + mArchive.toString());
3243 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003244 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003245 while (iter.hasNext()) {
3246 final StatusBarNotification sbn = iter.next();
3247 if (filter != null && !filter.matches(sbn)) continue;
3248 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003249 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003250 if (iter.hasNext()) pw.println(" ...");
3251 break;
3252 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003253 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003254
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003255 if (!zenOnly) {
3256 N = mEnqueuedNotifications.size();
3257 if (N > 0) {
3258 pw.println(" Enqueued Notification List:");
3259 for (int i = 0; i < N; i++) {
3260 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3261 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3262 nr.dump(pw, " ", getContext(), filter.redact);
3263 }
3264 pw.println(" ");
3265 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003266
3267 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003268 }
3269 }
3270
John Spurlock50806fc2014-07-15 10:22:02 -04003271 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003272 pw.println("\n Ranking Config:");
3273 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003274
John Spurlock50806fc2014-07-15 10:22:02 -04003275 pw.println("\n Notification listeners:");
3276 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003277 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3278 pw.print(" mListenersDisablingEffects: (");
3279 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003280 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003281 final int hint = mListenersDisablingEffects.keyAt(i);
3282 if (i > 0) pw.print(';');
3283 pw.print("hint[" + hint + "]:");
3284
3285 final ArraySet<ManagedServiceInfo> listeners =
3286 mListenersDisablingEffects.valueAt(i);
3287 final int listenerSize = listeners.size();
3288
3289 for (int j = 0; j < listenerSize; j++) {
3290 if (i > 0) pw.print(',');
3291 final ManagedServiceInfo listener = listeners.valueAt(i);
3292 pw.print(listener.component);
3293 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003294 }
3295 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003296 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003297 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003298 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003299
Julia Reynolds520df6e2017-02-13 09:05:10 -05003300 if (!filter.filtered || zenOnly) {
3301 pw.println("\n Zen Mode:");
3302 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3303 mZenModeHelper.dump(pw, " ");
3304
3305 pw.println("\n Zen Log:");
3306 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003307 }
3308
John Spurlocke77bb362014-04-26 10:24:59 -04003309 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003310 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003311
3312 pw.println("\n Group summaries:");
3313 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3314 NotificationRecord r = entry.getValue();
3315 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3316 if (mNotificationsByKey.get(r.getKey()) != r) {
3317 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003318 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003319 }
3320 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003321
3322 if (!zenOnly) {
3323 pw.println("\n Usage Stats:");
3324 mUsageStats.dump(pw, " ", filter);
3325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003326 }
3327 }
3328
Adam Lesinski182f73f2013-12-05 16:48:06 -08003329 /**
3330 * The private API only accessible to the system process.
3331 */
3332 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3333 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003334 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003335 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003336 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003337 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003338 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003339
3340 @Override
3341 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3342 int userId) {
3343 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003344 mHandler.post(new Runnable() {
3345 @Override
3346 public void run() {
3347 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003348 removeForegroundServiceFlagByListLocked(
3349 mEnqueuedNotifications, pkg, notificationId, userId);
3350 removeForegroundServiceFlagByListLocked(
3351 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003352 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003353 }
3354 });
3355 }
3356
Julia Reynolds88860ce2017-06-01 16:55:49 -04003357 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003358 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003359 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3360 int userId) {
3361 NotificationRecord r = findNotificationByListLocked(
3362 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003363 if (r == null) {
3364 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003365 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003366 StatusBarNotification sbn = r.sbn;
3367 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3368 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3369 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3370 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3371 sbn.getNotification().flags =
3372 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3373 mRankingHelper.sort(mNotificationList);
3374 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
Christoph Studer365e4c32014-09-18 20:35:36 +02003375 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003376 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003378 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04003379 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003380 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04003381 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003382 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3383 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04003384 }
John Spurlock7340fc82014-04-24 18:50:12 -04003385 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003386
Scott Greenwald9b05c612013-06-25 23:44:05 -04003387 final int userId = ActivityManager.handleIncomingUser(callingPid,
3388 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07003389 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07003390
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003391 if (pkg == null || notification == null) {
3392 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3393 + " id=" + id + " notification=" + notification);
3394 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003395
3396 // The system can post notifications for any package, let us resolve that.
3397 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3398
Julia Reynoldse46bb372016-03-17 11:05:58 -04003399 // Fix the notification as best we can.
3400 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003401 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06003402 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3403 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04003404 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04003405
3406 int canColorize = mPackageManagerClient.checkPermission(
3407 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3408 if (canColorize == PERMISSION_GRANTED) {
3409 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3410 } else {
3411 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3412 }
3413
Julia Reynoldse46bb372016-03-17 11:05:58 -04003414 } catch (NameNotFoundException e) {
3415 Slog.e(TAG, "Cannot create a context for sending app", e);
3416 return;
3417 }
3418
Chris Wren888b7a82016-06-17 15:47:19 -04003419 mUsageStats.registerEnqueuedByApp(pkg);
3420
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003421 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04003422 String channelId = notification.getChannelId();
3423 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3424 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05003425 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003426 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003427 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003428 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003429 final String noChannelStr = "No Channel found for "
3430 + "pkg=" + pkg
3431 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04003432 + ", id=" + id
3433 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003434 + ", opPkg=" + opPkg
3435 + ", callingUid=" + callingUid
3436 + ", userId=" + userId
3437 + ", incomingUserId=" + incomingUserId
3438 + ", notificationUid=" + notificationUid
3439 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003440 Log.e(TAG, noChannelStr);
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003441 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
Geoffrey Pitschcadb5dc2017-04-11 11:35:02 -04003442 "Failed to post notification on channel \"" + channelId + "\"\n" +
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003443 "See log for more details");
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003444 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003445 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003446
Chris Wrena61f1792016-08-04 11:24:42 -04003447 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003448 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003449 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003450 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Chris Wrena61f1792016-08-04 11:24:42 -04003451
Julia Reynolds5e702192017-08-18 09:22:40 -04003452 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3453 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003454 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07003455 }
3456
Felipe Lemedd85da62016-06-28 11:29:54 -07003457 // Whitelist pending intents.
3458 if (notification.allPendingIntents != null) {
3459 final int intentCount = notification.allPendingIntents.size();
3460 if (intentCount > 0) {
3461 final ActivityManagerInternal am = LocalServices
3462 .getService(ActivityManagerInternal.class);
3463 final long duration = LocalServices.getService(
3464 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3465 for (int i = 0; i < intentCount; i++) {
3466 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3467 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07003468 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3469 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07003470 }
3471 }
3472 }
3473 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07003474
Chris Wren47633422016-01-22 09:56:59 -05003475 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 }
3477
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003478 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003479 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003480 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003481 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3482 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003483 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04003484 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04003485 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003486 }
3487 }
3488
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003489 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3490 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003491 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003492 try {
3493 return getContext().getPackageManager()
3494 .getPackageUidAsUser(opPackageName, userId);
3495 } catch (NameNotFoundException e) {
3496 /* ignore */
3497 }
3498 }
3499 return callingUid;
3500 }
3501
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003502 /**
3503 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3504 *
3505 * Has side effects.
3506 */
3507 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04003508 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003509 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003510 final boolean isSystemNotification =
3511 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003512 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3513
3514 // Limit the number of notifications that any given package except the android
3515 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
3516 if (!isSystemNotification && !isNotificationFromListener) {
3517 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003518 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3519 // Ephemeral apps have some special constraints for notifications.
3520 // They are not allowed to create new notifications however they are allowed to
3521 // update notifications created by the system (e.g. a foreground service
3522 // notification).
3523 throw new SecurityException("Instant app " + pkg
3524 + " cannot create notifications");
3525 }
3526
3527 // rate limit updates that aren't completed progress notifications
3528 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04003529 && !r.getNotification().hasCompletedProgress()
3530 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003531
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003532 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3533 if (appEnqueueRate > mMaxPackageEnqueueRate) {
3534 mUsageStats.registerOverRateQuota(pkg);
3535 final long now = SystemClock.elapsedRealtime();
3536 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3537 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04003538 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003539 mLastOverRateLogTime = now;
3540 }
3541 return false;
3542 }
3543 }
3544
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003545 // limit the number of outstanding notificationrecords an app can have
3546 int count = getNotificationCountLocked(pkg, userId, id, tag);
3547 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3548 mUsageStats.registerOverCountQuota(pkg);
3549 Slog.e(TAG, "Package has already posted or enqueued " + count
3550 + " notifications. Not showing more. package=" + pkg);
3551 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003552 }
3553 }
3554 }
3555
3556 // snoozed apps
3557 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05003558 MetricsLogger.action(r.getLogMaker()
3559 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3560 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003561 if (DBG) {
3562 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3563 }
3564 mSnoozeHelper.update(userId, r);
3565 savePolicyFile();
3566 return false;
3567 }
3568
3569
3570 // blocked apps
3571 if (isBlocked(r, mUsageStats)) {
3572 return false;
3573 }
3574
3575 return true;
3576 }
3577
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003578 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3579 String excludedTag) {
3580 int count = 0;
3581 final int N = mNotificationList.size();
3582 for (int i = 0; i < N; i++) {
3583 final NotificationRecord existing = mNotificationList.get(i);
3584 if (existing.sbn.getPackageName().equals(pkg)
3585 && existing.sbn.getUserId() == userId) {
3586 if (existing.sbn.getId() == excludedId
3587 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3588 continue;
3589 }
3590 count++;
3591 }
3592 }
3593 final int M = mEnqueuedNotifications.size();
3594 for (int i = 0; i < M; i++) {
3595 final NotificationRecord existing = mEnqueuedNotifications.get(i);
3596 if (existing.sbn.getPackageName().equals(pkg)
3597 && existing.sbn.getUserId() == userId) {
3598 count++;
3599 }
3600 }
3601 return count;
3602 }
3603
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003604 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3605 final String pkg = r.sbn.getPackageName();
3606 final int callingUid = r.sbn.getUid();
3607
3608 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3609 if (isPackageSuspended) {
3610 Slog.e(TAG, "Suppressing notification from package due to package "
3611 + "suspended by administrator.");
3612 usageStats.registerSuspendedByAdmin(r);
3613 return isPackageSuspended;
3614 }
3615
Julia Reynolds4da79702017-06-01 11:06:10 -04003616 final boolean isBlocked =
3617 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04003618 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003619 if (isBlocked) {
3620 Slog.e(TAG, "Suppressing notification from package by user request.");
3621 usageStats.registerBlocked(r);
3622 }
3623 return isBlocked;
3624 }
3625
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003626 protected class SnoozeNotificationRunnable implements Runnable {
3627 private final String mKey;
3628 private final long mDuration;
3629 private final String mSnoozeCriterionId;
3630
3631 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3632 mKey = key;
3633 mDuration = duration;
3634 mSnoozeCriterionId = snoozeCriterionId;
3635 }
3636
3637 @Override
3638 public void run() {
3639 synchronized (mNotificationLock) {
3640 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3641 if (r != null) {
3642 snoozeLocked(r);
3643 }
3644 }
3645 }
3646
Julia Reynolds88860ce2017-06-01 16:55:49 -04003647 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003648 void snoozeLocked(NotificationRecord r) {
3649 if (r.sbn.isGroup()) {
3650 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3651 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3652 if (r.getNotification().isGroupSummary()) {
3653 // snooze summary and all children
3654 for (int i = 0; i < groupNotifications.size(); i++) {
3655 snoozeNotificationLocked(groupNotifications.get(i));
3656 }
3657 } else {
3658 // if there is a valid summary for this group, and we are snoozing the only
3659 // child, also snooze the summary
3660 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3661 if (groupNotifications.size() != 2) {
3662 snoozeNotificationLocked(r);
3663 } else {
3664 // snooze summary and the one child
3665 for (int i = 0; i < groupNotifications.size(); i++) {
3666 snoozeNotificationLocked(groupNotifications.get(i));
3667 }
3668 }
3669 } else {
3670 snoozeNotificationLocked(r);
3671 }
3672 }
3673 } else {
3674 // just snooze the one notification
3675 snoozeNotificationLocked(r);
3676 }
3677 }
3678
Julia Reynolds88860ce2017-06-01 16:55:49 -04003679 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003680 void snoozeNotificationLocked(NotificationRecord r) {
3681 MetricsLogger.action(r.getLogMaker()
3682 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3683 .setType(MetricsEvent.TYPE_CLOSE)
3684 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3685 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04003686 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003687 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003688 updateLightsLocked();
3689 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003690 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003691 mSnoozeHelper.snooze(r);
3692 } else {
3693 mSnoozeHelper.snooze(r, mDuration);
3694 }
3695 savePolicyFile();
3696 }
3697 }
3698
Julia Reynoldsbaff4002016-12-15 11:34:26 -05003699 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05003700 private final NotificationRecord r;
3701 private final int userId;
3702
3703 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3704 this.userId = userId;
3705 this.r = r;
3706 };
3707
3708 @Override
3709 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003710 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05003711 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05003712 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05003713
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003714 final StatusBarNotification n = r.sbn;
3715 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3716 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3717 if (old != null) {
3718 // Retain ranking information from previous record
3719 r.copyRankingInformation(old);
3720 }
3721
3722 final int callingUid = n.getUid();
3723 final int callingPid = n.getInitialPid();
3724 final Notification notification = n.getNotification();
3725 final String pkg = n.getPackageName();
3726 final int id = n.getId();
3727 final String tag = n.getTag();
3728
3729 // Handle grouped notifications and bail out early if we
3730 // can to avoid extracting signals.
3731 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3732
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003733 // if this is a group child, unsnooze parent summary
3734 if (n.isGroup() && notification.isGroupChild()) {
3735 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3736 }
3737
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003738 // This conditional is a dirty hack to limit the logging done on
3739 // behalf of the download manager without affecting other apps.
3740 if (!pkg.equals("com.android.providers.downloads")
3741 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3742 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05003743 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003744 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05003745 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003746 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3747 pkg, id, tag, userId, notification.toString(),
3748 enqueueStatus);
3749 }
Chris Wren6676dab2016-12-21 18:26:27 -05003750
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003751 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05003752
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003753 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003754 if (mAssistants.isEnabled()) {
3755 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003756 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003757 DELAY_FOR_ASSISTANT_TIME);
3758 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003759 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003760 }
3761 }
3762 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003763 }
3764
3765 protected class PostNotificationRunnable implements Runnable {
3766 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003767
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003768 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003769 this.key = key;
3770 }
3771
3772 @Override
3773 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003774 synchronized (mNotificationLock) {
3775 try {
3776 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003777 int N = mEnqueuedNotifications.size();
3778 for (int i = 0; i < N; i++) {
3779 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3780 if (Objects.equals(key, enqueued.getKey())) {
3781 r = enqueued;
3782 break;
Chris Wren6676dab2016-12-21 18:26:27 -05003783 }
Chris Wren6676dab2016-12-21 18:26:27 -05003784 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003785 if (r == null) {
3786 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3787 return;
3788 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003789 NotificationRecord old = mNotificationsByKey.get(key);
3790 final StatusBarNotification n = r.sbn;
3791 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05003792 int index = indexOfNotificationLocked(n.getKey());
3793 if (index < 0) {
3794 mNotificationList.add(r);
3795 mUsageStats.registerPostedByApp(r);
3796 } else {
3797 old = mNotificationList.get(index);
3798 mNotificationList.set(index, r);
3799 mUsageStats.registerUpdatedByApp(r, old);
3800 // Make sure we don't lose the foreground service state.
3801 notification.flags |=
3802 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3803 r.isUpdate = true;
3804 }
3805
3806 mNotificationsByKey.put(n.getKey(), r);
3807
3808 // Ensure if this is a foreground service that the proper additional
3809 // flags are set.
3810 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3811 notification.flags |= Notification.FLAG_ONGOING_EVENT
3812 | Notification.FLAG_NO_CLEAR;
3813 }
3814
3815 applyZenModeLocked(r);
3816 mRankingHelper.sort(mNotificationList);
3817
3818 if (notification.getSmallIcon() != null) {
3819 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3820 mListeners.notifyPostedLocked(n, oldSbn);
Julia Reynolds8aebf352017-06-26 11:35:33 -04003821 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
3822 mHandler.post(new Runnable() {
3823 @Override
3824 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003825 mGroupHelper.onNotificationPosted(
3826 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04003827 }
3828 });
3829 }
Chris Wren6676dab2016-12-21 18:26:27 -05003830 } else {
3831 Slog.e(TAG, "Not posting notification without small icon: " + notification);
3832 if (old != null && !old.isCanceled) {
3833 mListeners.notifyRemovedLocked(n,
Julia Reynoldsf619bc52017-03-17 08:32:23 -04003834 NotificationListenerService.REASON_ERROR);
Chris Wren6676dab2016-12-21 18:26:27 -05003835 mHandler.post(new Runnable() {
3836 @Override
3837 public void run() {
3838 mGroupHelper.onNotificationRemoved(n);
3839 }
3840 });
3841 }
3842 // ATTENTION: in a future release we will bail out here
3843 // so that we do not play sounds, show lights, etc. for invalid
3844 // notifications
3845 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3846 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05003847 }
Chris Wren47633422016-01-22 09:56:59 -05003848
Chris Wren6676dab2016-12-21 18:26:27 -05003849 buzzBeepBlinkLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003850 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003851 int N = mEnqueuedNotifications.size();
3852 for (int i = 0; i < N; i++) {
3853 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3854 if (Objects.equals(key, enqueued.getKey())) {
3855 mEnqueuedNotifications.remove(i);
3856 break;
3857 }
3858 }
Chris Wren6676dab2016-12-21 18:26:27 -05003859 }
Chris Wren47633422016-01-22 09:56:59 -05003860 }
3861 }
3862 }
3863
Christoph Studer265c1052014-07-23 17:14:33 +02003864 /**
3865 * Ensures that grouped notification receive their special treatment.
3866 *
3867 * <p>Cancels group children if the new notification causes a group to lose
3868 * its summary.</p>
3869 *
3870 * <p>Updates mSummaryByGroupKey.</p>
3871 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04003872 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02003873 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3874 int callingUid, int callingPid) {
3875 StatusBarNotification sbn = r.sbn;
3876 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07003877 if (n.isGroupSummary() && !sbn.isAppGroup()) {
3878 // notifications without a group shouldn't be a summary, otherwise autobundling can
3879 // lead to bugs
3880 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3881 }
3882
Christoph Studer265c1052014-07-23 17:14:33 +02003883 String group = sbn.getGroupKey();
3884 boolean isSummary = n.isGroupSummary();
3885
3886 Notification oldN = old != null ? old.sbn.getNotification() : null;
3887 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3888 boolean oldIsSummary = old != null && oldN.isGroupSummary();
3889
3890 if (oldIsSummary) {
3891 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3892 if (removedSummary != old) {
3893 String removedKey =
3894 removedSummary != null ? removedSummary.getKey() : "<null>";
3895 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3896 ", removed=" + removedKey);
3897 }
3898 }
3899 if (isSummary) {
3900 mSummaryByGroupKey.put(group, r);
3901 }
3902
3903 // Clear out group children of the old notification if the update
3904 // causes the group summary to go away. This happens when the old
3905 // notification was a summary and the new one isn't, or when the old
3906 // notification was a summary and its group key changed.
3907 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04003908 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
3909 null);
Christoph Studer265c1052014-07-23 17:14:33 +02003910 }
3911 }
3912
Chris Wren93bb8b82016-03-29 14:35:05 -04003913 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04003914 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05003915 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04003916 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05003917 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3918 REQUEST_CODE_TIMEOUT,
3919 new Intent(ACTION_NOTIFICATION_TIMEOUT)
3920 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3921 .appendPath(record.getKey()).build())
3922 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3923 .putExtra(EXTRA_KEY, record.getKey()),
3924 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05003925 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04003926 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05003927 }
3928 }
3929
3930 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04003931 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04003932 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04003933 boolean buzz = false;
3934 boolean beep = false;
3935 boolean blink = false;
3936
Chris Wrena3446562014-06-03 18:11:47 -04003937 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04003938 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04003939
3940 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04003941 final boolean aboveThreshold =
3942 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04003943
3944 // Remember if this notification already owns the notification channels.
3945 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3946 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04003947 // These are set inside the conditional if the notification is allowed to make noise.
3948 boolean hasValidVibrate = false;
3949 boolean hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04003950
Julia Reynolds76c096d2017-06-19 08:16:04 -04003951 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04003952 // If the notification will appear in the status bar, it should send an accessibility
3953 // event
3954 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
Chris Wren93bb8b82016-03-29 14:35:05 -04003955 sendAccessibilityEvent(notification, record.sbn.getPackageName());
Julia Reynolds7c96b582017-05-25 12:35:36 -04003956 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04003957 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04003958 Uri soundUri = record.getSound();
3959 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
Julia Reynolds76c096d2017-06-19 08:16:04 -04003960
Julia Reynolds7c96b582017-05-25 12:35:36 -04003961 long[] vibration = record.getVibration();
3962 // Demote sound to vibration if vibration missing & phone in vibration mode.
3963 if (vibration == null
3964 && hasValidSound
3965 && (mAudioManager.getRingerModeInternal()
3966 == AudioManager.RINGER_MODE_VIBRATE)) {
3967 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04003968 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04003969 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01003970
Julia Reynolds76c096d2017-06-19 08:16:04 -04003971 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
3972
3973 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
3974 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04003975 if (hasValidSound) {
3976 mSoundNotificationKey = key;
3977 if (mInCall) {
3978 playInCallNotification();
3979 beep = true;
3980 } else {
3981 beep = playSound(record, soundUri);
3982 }
3983 }
Chris Wren93bb8b82016-03-29 14:35:05 -04003984
Julia Reynolds7c96b582017-05-25 12:35:36 -04003985 final boolean ringerModeSilent =
3986 mAudioManager.getRingerModeInternal()
3987 == AudioManager.RINGER_MODE_SILENT;
3988 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
3989 mVibrateNotificationKey = key;
3990
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07003991 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04003992 }
Chris Wrena3446562014-06-03 18:11:47 -04003993 }
3994 }
Chris Wren93bb8b82016-03-29 14:35:05 -04003995 }
3996 // If a notification is updated to remove the actively playing sound or vibrate,
3997 // cancel that feedback now
3998 if (wasBeep && !hasValidSound) {
3999 clearSoundLocked();
4000 }
4001 if (wasBuzz && !hasValidVibrate) {
4002 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004003 }
4004
4005 // light
4006 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004007 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004008 if (record.getLight() != null && aboveThreshold
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004009 && ((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05004010 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004011 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004012 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004013 if (mUseAttentionLight) {
4014 mAttentionLight.pulse();
4015 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004016 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004017 } else if (wasShowLights) {
4018 updateLightsLocked();
4019 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004020 if (buzz || beep || blink) {
Julia Reynolds445cfa82017-05-08 15:41:45 -04004021 MetricsLogger.action(record.getLogMaker()
4022 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4023 .setType(MetricsEvent.TYPE_OPEN)
4024 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4025 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004026 }
Chris Wrena3446562014-06-03 18:11:47 -04004027 }
4028
Julia Reynolds88860ce2017-06-01 16:55:49 -04004029 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004030 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004031 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004032 final Notification notification = record.getNotification();
4033 if(record.isUpdate
4034 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4035 return true;
4036 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004037
Julia Reynolds76c096d2017-06-19 08:16:04 -04004038 // muted by listener
4039 final String disableEffects = disableNotificationEffects(record);
4040 if (disableEffects != null) {
4041 ZenLog.traceDisableEffects(record, disableEffects);
4042 return true;
4043 }
4044
4045 // suppressed due to DND
4046 if (record.isIntercepted()) {
4047 return true;
4048 }
4049
4050 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004051 if (record.sbn.isGroup()) {
Julia Reynolds30203152017-05-26 13:36:31 -04004052 return notification.suppressAlertingDueToGrouping();
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004053 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004054
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004055 // Suppressed for being too recently noisy
4056 final String pkg = record.sbn.getPackageName();
4057 if (mUsageStats.isAlertRateLimited(pkg)) {
4058 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4059 return true;
4060 }
4061
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004062 return false;
4063 }
4064
Julia Reynolds0c299d42016-11-15 14:37:04 -05004065 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4066 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4067 // do not play notifications if there is a user of exclusive audio focus
Julia Reynolds2143e5d2017-01-17 16:28:48 -05004068 // or the device is in vibrate mode
4069 if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
4070 != AudioManager.RINGER_MODE_VIBRATE) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004071 final long identity = Binder.clearCallingIdentity();
4072 try {
4073 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4074 if (player != null) {
4075 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4076 + " with attributes " + record.getAudioAttributes());
4077 player.playAsync(soundUri, record.sbn.getUser(), looping,
4078 record.getAudioAttributes());
4079 return true;
4080 }
4081 } catch (RemoteException e) {
4082 } finally {
4083 Binder.restoreCallingIdentity(identity);
4084 }
4085 }
4086 return false;
4087 }
4088
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004089 private boolean playVibration(final NotificationRecord record, long[] vibration,
4090 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004091 // Escalate privileges so we can use the vibrator even if the
4092 // notifying app does not have the VIBRATE permission.
4093 long identity = Binder.clearCallingIdentity();
4094 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004095 final VibrationEffect effect;
4096 try {
4097 final boolean insistent =
4098 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4099 effect = VibrationEffect.createWaveform(
4100 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4101 } catch (IllegalArgumentException e) {
4102 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4103 Arrays.toString(vibration));
4104 return false;
4105 }
4106 if (delayVibForSound) {
4107 new Thread(() -> {
4108 // delay the vibration by the same amount as the notification sound
4109 final int waitMs = mAudioManager.getFocusRampTimeMs(
4110 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4111 record.getAudioAttributes());
4112 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4113 try {
4114 Thread.sleep(waitMs);
4115 } catch (InterruptedException e) { }
4116 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4117 effect, record.getAudioAttributes());
4118 }).start();
4119 } else {
4120 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4121 effect, record.getAudioAttributes());
4122 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004123 return true;
4124 } finally{
4125 Binder.restoreCallingIdentity(identity);
4126 }
4127 }
4128
Julia Reynolds7c96b582017-05-25 12:35:36 -04004129 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4130 final int currentUser;
4131 final long token = Binder.clearCallingIdentity();
4132 try {
4133 currentUser = ActivityManager.getCurrentUser();
4134 } finally {
4135 Binder.restoreCallingIdentity(token);
4136 }
4137 return (record.getUserId() == UserHandle.USER_ALL ||
4138 record.getUserId() == currentUser ||
4139 mUserProfiles.isCurrentProfile(record.getUserId()));
4140 }
4141
Beverly5d463b62017-07-26 14:13:40 -04004142 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01004143 new Thread() {
4144 @Override
4145 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04004146 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01004147 try {
Beverly5d463b62017-07-26 14:13:40 -04004148 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4149 if (player != null) {
4150 player.play(new Binder(), mInCallNotificationUri,
4151 mInCallNotificationAudioAttributes,
4152 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01004153 }
Beverly5d463b62017-07-26 14:13:40 -04004154 } catch (RemoteException e) {
4155 } finally {
4156 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01004157 }
4158 }
4159 }.start();
4160 }
4161
Julia Reynolds88860ce2017-06-01 16:55:49 -04004162 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004163 void showNextToastLocked() {
4164 ToastRecord record = mToastQueue.get(0);
4165 while (record != null) {
4166 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4167 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004168 record.callback.show(record.token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004169 scheduleTimeoutLocked(record);
4170 return;
4171 } catch (RemoteException e) {
4172 Slog.w(TAG, "Object died trying to show notification " + record.callback
4173 + " in package " + record.pkg);
4174 // remove it from the list and let the process die
4175 int index = mToastQueue.indexOf(record);
4176 if (index >= 0) {
4177 mToastQueue.remove(index);
4178 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004179 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004180 if (mToastQueue.size() > 0) {
4181 record = mToastQueue.get(0);
4182 } else {
4183 record = null;
4184 }
4185 }
4186 }
4187 }
4188
Julia Reynolds88860ce2017-06-01 16:55:49 -04004189 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004190 void cancelToastLocked(int index) {
4191 ToastRecord record = mToastQueue.get(index);
4192 try {
4193 record.callback.hide();
4194 } catch (RemoteException e) {
4195 Slog.w(TAG, "Object died trying to hide notification " + record.callback
4196 + " in package " + record.pkg);
4197 // don't worry about this, we're about to remove it from
4198 // the list anyway
4199 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004200
4201 ToastRecord lastToast = mToastQueue.remove(index);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07004202 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004203
4204 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004205 if (mToastQueue.size() > 0) {
4206 // Show the next one. If the callback fails, this will remove
4207 // it from the list, so don't assume that the list hasn't changed
4208 // after this point.
4209 showNextToastLocked();
4210 }
4211 }
4212
Julia Reynolds88860ce2017-06-01 16:55:49 -04004213 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004214 private void scheduleTimeoutLocked(ToastRecord r)
4215 {
4216 mHandler.removeCallbacksAndMessages(r);
4217 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4218 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4219 mHandler.sendMessageDelayed(m, delay);
4220 }
4221
4222 private void handleTimeout(ToastRecord record)
4223 {
4224 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4225 synchronized (mToastQueue) {
4226 int index = indexOfToastLocked(record.pkg, record.callback);
4227 if (index >= 0) {
4228 cancelToastLocked(index);
4229 }
4230 }
4231 }
4232
Julia Reynolds88860ce2017-06-01 16:55:49 -04004233 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004234 int indexOfToastLocked(String pkg, ITransientNotification callback)
4235 {
4236 IBinder cbak = callback.asBinder();
4237 ArrayList<ToastRecord> list = mToastQueue;
4238 int len = list.size();
4239 for (int i=0; i<len; i++) {
4240 ToastRecord r = list.get(i);
Beverly4ee785b2017-08-11 12:49:56 -04004241 if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4242 return i;
4243 }
4244 }
4245 return -1;
4246 }
4247
4248 @GuardedBy("mToastQueue")
4249 int indexOfToastPackageLocked(String pkg)
4250 {
4251 ArrayList<ToastRecord> list = mToastQueue;
4252 int len = list.size();
4253 for (int i=0; i<len; i++) {
4254 ToastRecord r = list.get(i);
4255 if (r.pkg.equals(pkg)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004256 return i;
4257 }
4258 }
4259 return -1;
4260 }
4261
Julia Reynolds88860ce2017-06-01 16:55:49 -04004262 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004263 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08004264 {
4265 int toastCount = 0; // toasts from this pid
4266 ArrayList<ToastRecord> list = mToastQueue;
4267 int N = list.size();
4268 for (int i=0; i<N; i++) {
4269 ToastRecord r = list.get(i);
4270 if (r.pid == pid) {
4271 toastCount++;
4272 }
4273 }
4274 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07004275 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08004276 } catch (RemoteException e) {
4277 // Shouldn't happen.
4278 }
4279 }
4280
Chris Wrenf9536642014-04-17 10:01:54 -04004281 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004282 if (!(message.obj instanceof RankingReconsideration)) return;
4283 RankingReconsideration recon = (RankingReconsideration) message.obj;
4284 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04004285 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004286 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004287 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4288 if (record == null) {
4289 return;
Chris Wrenf9536642014-04-17 10:01:54 -04004290 }
Chris Wren333a61c2014-05-28 16:40:57 -04004291 int indexBefore = findNotificationRecordIndexLocked(record);
4292 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004293 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004294 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04004295 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04004296 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04004297 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04004298 int indexAfter = findNotificationRecordIndexLocked(record);
4299 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004300 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004301 int visibilityAfter = record.getPackageVisibilityOverride();
4302 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4303 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004304 if (interceptBefore && !interceptAfter
4305 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04004306 buzzBeepBlinkLocked(record);
4307 }
Chris Wrenf9536642014-04-17 10:01:54 -04004308 }
Chris Wren333a61c2014-05-28 16:40:57 -04004309 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004310 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04004311 }
4312 }
4313
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004314 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04004315 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004316 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04004317 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004318 // Any field that can change via one of the extractors needs to be added here.
4319 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004320 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05004321 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004322 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4323 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4324 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4325 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04004326 for (int i = 0; i < N; i++) {
4327 final NotificationRecord r = mNotificationList.get(i);
4328 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004329 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05004330 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004331 channelBefore.add(r.getChannel());
4332 groupKeyBefore.add(r.getGroupKey());
4333 overridePeopleBefore.add(r.getPeopleOverride());
4334 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Chris Wren54bbef42014-07-09 18:37:56 -04004335 mRankingHelper.extractSignals(r);
4336 }
Chris Wren19a02b02015-12-22 10:34:22 -05004337 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04004338 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004339 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004340 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05004341 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004342 || showBadges[i] != r.canShowBadge()
4343 || !Objects.equals(channelBefore.get(i), r.getChannel())
4344 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4345 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
4346 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())) {
4347 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04004348 return;
4349 }
4350 }
4351 }
4352 }
4353
Julia Reynolds88860ce2017-06-01 16:55:49 -04004354 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004355 private void recordCallerLocked(NotificationRecord record) {
4356 if (mZenModeHelper.isCall(record)) {
4357 mZenModeHelper.recordCaller(record);
4358 }
4359 }
4360
Christoph Studerd5092bc2014-07-03 17:47:58 +02004361 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04004362 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04004363 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02004364 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004365 if (record.isIntercepted()) {
Julia Reynoldsd5607292016-02-05 15:25:58 -05004366 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4367 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4368 | (mZenModeHelper.shouldSuppressWhenScreenOn()
4369 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004370 record.setSuppressedVisualEffects(suppressed);
Julia Reynolds445cfa82017-05-08 15:41:45 -04004371 } else {
4372 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004373 }
Chris Wren333a61c2014-05-28 16:40:57 -04004374 }
4375
Julia Reynolds88860ce2017-06-01 16:55:49 -04004376 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04004377 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04004378 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04004379 }
4380
Chris Wrenf9536642014-04-17 10:01:54 -04004381 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004382 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04004383 mListeners.notifyRankingUpdateLocked();
Chris Wrenf9536642014-04-17 10:01:54 -04004384 }
4385 }
4386
John Spurlockd8afe3c2014-08-01 14:04:07 -04004387 private void scheduleListenerHintsChanged(int state) {
4388 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4389 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04004390 }
4391
Christoph Studer85a384b2014-08-27 20:16:15 +02004392 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4393 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4394 mHandler.obtainMessage(
4395 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4396 listenerInterruptionFilter,
4397 0).sendToTarget();
4398 }
4399
John Spurlockd8afe3c2014-08-01 14:04:07 -04004400 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004401 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004402 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004403 }
4404 }
4405
Christoph Studer85a384b2014-08-27 20:16:15 +02004406 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004407 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02004408 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4409 }
4410 }
4411
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004412 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08004413 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004414 public WorkerHandler(Looper looper) {
4415 super(looper);
4416 }
4417
Adam Lesinski182f73f2013-12-05 16:48:06 -08004418 @Override
4419 public void handleMessage(Message msg)
4420 {
4421 switch (msg.what)
4422 {
4423 case MESSAGE_TIMEOUT:
4424 handleTimeout((ToastRecord)msg.obj);
4425 break;
John Spurlock056c5192014-04-20 21:52:01 -04004426 case MESSAGE_SAVE_POLICY_FILE:
4427 handleSavePolicyFile();
4428 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004429 case MESSAGE_SEND_RANKING_UPDATE:
4430 handleSendRankingUpdate();
4431 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04004432 case MESSAGE_LISTENER_HINTS_CHANGED:
4433 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04004434 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02004435 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4436 handleListenerInterruptionFilterChanged(msg.arg1);
4437 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004438 }
4439 }
4440
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004441 protected void scheduleSendRankingUpdate() {
4442 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4443 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4444 sendMessage(m);
4445 }
4446 }
4447
Chris Wrenf9536642014-04-17 10:01:54 -04004448 }
4449
Chris Wren51017d02015-12-15 15:34:46 -05004450 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04004451 {
Chris Wren51017d02015-12-15 15:34:46 -05004452 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04004453 super(looper);
4454 }
4455
4456 @Override
4457 public void handleMessage(Message msg) {
4458 switch (msg.what) {
4459 case MESSAGE_RECONSIDER_RANKING:
4460 handleRankingReconsideration(msg);
4461 break;
Chris Wren51017d02015-12-15 15:34:46 -05004462 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004463 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04004464 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08004465 }
4466 }
Chris Wren51017d02015-12-15 15:34:46 -05004467
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004468 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05004469 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05004470 Message msg = Message.obtain();
4471 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05004472 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05004473 }
4474
4475 public void requestReconsideration(RankingReconsideration recon) {
4476 Message m = Message.obtain(this,
4477 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4478 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4479 sendMessageDelayed(m, delay);
4480 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004481 }
4482
Adam Lesinski182f73f2013-12-05 16:48:06 -08004483 // Notifications
4484 // ============================================================================
4485 static int clamp(int x, int low, int high) {
4486 return (x < low) ? low : ((x > high) ? high : x);
4487 }
4488
4489 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4490 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
svetoslavganov75986cf2009-05-14 22:28:01 -07004491 if (!manager.isEnabled()) {
4492 return;
4493 }
4494
4495 AccessibilityEvent event =
4496 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4497 event.setPackageName(packageName);
4498 event.setClassName(Notification.class.getName());
4499 event.setParcelableData(notification);
4500 CharSequence tickerText = notification.tickerText;
4501 if (!TextUtils.isEmpty(tickerText)) {
4502 event.getText().add(tickerText);
4503 }
4504
4505 manager.sendAccessibilityEvent(event);
4506 }
4507
Julia Reynolds0839c022017-06-15 15:24:01 -04004508 /**
4509 * Removes all NotificationsRecords with the same key as the given notification record
4510 * from both lists. Do not call this method while iterating over either list.
4511 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004512 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04004513 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4514 // Remove from both lists, either list could have a separate Record for what is
4515 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004516 boolean wasPosted = false;
4517 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04004518 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4519 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004520 mNotificationList.remove(recordInList);
4521 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004522 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004523 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004524 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004525 != null) {
4526 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004527 }
Julia Reynolds0839c022017-06-15 15:24:01 -04004528 return wasPosted;
4529 }
4530
4531 @GuardedBy("mNotificationLock")
4532 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04004533 boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04004534 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004535
4536 // Record caller.
4537 recordCallerLocked(r);
4538
Joe Onorato46439ce2010-11-19 13:56:21 -08004539 // tell the app
4540 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004541 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08004542 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004543 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08004544 } catch (PendingIntent.CanceledException ex) {
4545 // do nothing - there's no relevant way to recover, and
4546 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04004547 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08004548 }
4549 }
4550 }
4551
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004552 // Only cancel these if this notification actually got to be posted.
4553 if (wasPosted) {
4554 // status bar
4555 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004556 if (reason != REASON_SNOOZED) {
4557 r.isCanceled = true;
4558 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004559 mListeners.notifyRemovedLocked(r.sbn, reason);
4560 mHandler.post(new Runnable() {
4561 @Override
4562 public void run() {
4563 mGroupHelper.onNotificationRemoved(r.sbn);
4564 }
4565 });
4566 }
4567
4568 // sound
4569 if (canceledKey.equals(mSoundNotificationKey)) {
4570 mSoundNotificationKey = null;
4571 final long identity = Binder.clearCallingIdentity();
4572 try {
4573 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4574 if (player != null) {
4575 player.stopAsync();
4576 }
4577 } catch (RemoteException e) {
4578 } finally {
4579 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004580 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004582
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004583 // vibrate
4584 if (canceledKey.equals(mVibrateNotificationKey)) {
4585 mVibrateNotificationKey = null;
4586 long identity = Binder.clearCallingIdentity();
4587 try {
4588 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07004589 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004590 finally {
4591 Binder.restoreCallingIdentity(identity);
4592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004593 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004594
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004595 // light
4596 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004597 }
4598
Christoph Studer546bec82014-03-14 12:17:12 +01004599 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04004600 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01004601 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04004602 case REASON_CANCEL:
4603 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01004604 case REASON_LISTENER_CANCEL:
4605 case REASON_LISTENER_CANCEL_ALL:
4606 mUsageStats.registerDismissedByUser(r);
4607 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05004608 case REASON_APP_CANCEL:
4609 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01004610 mUsageStats.registerRemovedByApp(r);
4611 break;
Christoph Studer546bec82014-03-14 12:17:12 +01004612 }
4613
Christoph Studer265c1052014-07-23 17:14:33 +02004614 String groupKey = r.getGroupKey();
4615 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004616 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02004617 mSummaryByGroupKey.remove(groupKey);
4618 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04004619 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4620 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4621 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04004622 }
Christoph Studercef37cf2014-07-25 14:18:17 +02004623
Daniel Sandler23d7c702013-03-07 16:32:06 -05004624 // Save it for users of getHistoricalNotifications()
4625 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02004626
Chris Wren6650e572015-05-15 17:19:25 -04004627 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -05004628 MetricsLogger.action(r.getLogMaker(now)
4629 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4630 .setType(MetricsEvent.TYPE_DISMISS)
4631 .setSubtype(reason));
Chris Wrene6ddb8a2015-05-27 15:21:00 -04004632 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04004633 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 }
4635
4636 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07004637 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004638 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 */
John Spurlocke6a7d932014-03-13 12:29:00 -04004640 void cancelNotification(final int callingUid, final int callingPid,
4641 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004642 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04004643 final int userId, final int reason, final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004644 // In enqueueNotificationInternal notifications are added by scheduling the
4645 // work on the worker handler. Hence, we also schedule the cancel on this
4646 // handler to avoid a scenario where an add notification call followed by a
4647 // remove notification call ends up in not removing the notification.
4648 mHandler.post(new Runnable() {
4649 @Override
4650 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02004651 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08004652 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4653 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004654
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004655 synchronized (mNotificationLock) {
4656 // Look for the notification, searching both the posted and enqueued lists.
4657 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4658 if (r != null) {
4659 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004660
Christoph Studer546bec82014-03-14 12:17:12 +01004661 // Ideally we'd do this in the caller of this method. However, that would
4662 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04004663 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01004664 mUsageStats.registerClickedByUser(r);
4665 }
4666
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004667 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4668 return;
4669 }
4670 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4671 return;
4672 }
4673
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004674 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04004675 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004676 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02004677 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04004678 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004679 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004680 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004681 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004682 if (reason != REASON_SNOOZED) {
4683 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4684 if (wasSnoozed) {
4685 savePolicyFile();
4686 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004687 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004690 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004691 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004692 }
4693
4694 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07004695 * Determine whether the userId applies to the notification in question, either because
4696 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4697 */
4698 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4699 return
4700 // looking for USER_ALL notifications? match everything
4701 userId == UserHandle.USER_ALL
4702 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004703 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07004704 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004705 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07004706 }
4707
4708 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004709 * Determine whether the userId applies to the notification in question, either because
4710 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01004711 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004712 */
Kenny Guy2a764942014-04-02 13:29:20 +01004713 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00004714 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04004715 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004716 }
4717
4718 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05004719 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004720 * {@code mustHaveFlags}.
4721 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004722 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004723 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04004724 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004725 mHandler.post(new Runnable() {
4726 @Override
4727 public void run() {
4728 String listenerName = listener == null ? null : listener.component.toShortString();
4729 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4730 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4731 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004732
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004733 // Why does this parameter exist? Do we actually want to execute the above if doit
4734 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004735 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004736 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004737 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004738
4739 synchronized (mNotificationLock) {
4740 FlagChecker flagChecker = (int flags) -> {
4741 if ((flags & mustHaveFlags) != mustHaveFlags) {
4742 return false;
4743 }
4744 if ((flags & mustNotHaveFlags) != 0) {
4745 return false;
4746 }
4747 return true;
4748 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004749 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4750 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4751 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04004752 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004753 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4754 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4755 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04004756 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004757 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02004758 }
4759 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004760 });
4761 }
4762
4763 private interface FlagChecker {
4764 // Returns false if these flags do not pass the defined flag test.
4765 public boolean apply(int flags);
4766 }
4767
Julia Reynolds88860ce2017-06-01 16:55:49 -04004768 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004769 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4770 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4771 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04004772 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004773 ArrayList<NotificationRecord> canceledNotifications = null;
4774 for (int i = notificationList.size() - 1; i >= 0; --i) {
4775 NotificationRecord r = notificationList.get(i);
4776 if (includeCurrentProfiles) {
4777 if (!notificationMatchesCurrentProfiles(r, userId)) {
4778 continue;
4779 }
4780 } else if (!notificationMatchesUserId(r, userId)) {
4781 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004782 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004783 // Don't remove notifications to all, if there's no package name specified
4784 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4785 continue;
4786 }
4787 if (!flagChecker.apply(r.getFlags())) {
4788 continue;
4789 }
4790 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4791 continue;
4792 }
4793 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4794 continue;
4795 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004796 if (canceledNotifications == null) {
4797 canceledNotifications = new ArrayList<>();
4798 }
Julia Reynolds0839c022017-06-15 15:24:01 -04004799 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04004800 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004801 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004802 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004803 }
4804 if (canceledNotifications != null) {
4805 final int M = canceledNotifications.size();
4806 for (int i = 0; i < M; i++) {
4807 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04004808 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004809 }
4810 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004811 }
4812 }
4813
Julia Reynolds50989772017-02-23 14:32:16 -05004814 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004815 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05004816 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004817 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05004818 return;
4819 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004820
Julia Reynolds79672302017-01-12 08:30:16 -05004821 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05004822 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4823 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05004824 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004825 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004826 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05004827 }
4828
4829 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4830 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05004831 if (DBG) {
4832 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4833 }
Julia Reynolds79672302017-01-12 08:30:16 -05004834 mSnoozeHelper.repost(key);
4835 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05004836 }
4837
Julia Reynolds88860ce2017-06-01 16:55:49 -04004838 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07004839 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04004840 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004841 mHandler.post(new Runnable() {
4842 @Override
4843 public void run() {
4844 synchronized (mNotificationLock) {
4845 String listenerName =
4846 listener == null ? null : listener.component.toShortString();
4847 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4848 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01004849
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004850 FlagChecker flagChecker = (int flags) -> {
4851 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4852 != 0) {
4853 return false;
4854 }
4855 return true;
4856 };
4857
4858 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4859 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4860 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04004861 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004862 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4863 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4864 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04004865 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004866 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00004867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004868 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004869 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004870 }
4871
Christoph Studere4ef156b2014-07-04 18:41:57 +02004872 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04004873 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02004874 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04004875 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02004876 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02004877 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02004878 return;
4879 }
4880
4881 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02004882
4883 if (pkg == null) {
4884 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4885 return;
4886 }
4887
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004888 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04004889 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004890 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04004891 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004892 }
4893
Julia Reynolds88860ce2017-06-01 16:55:49 -04004894 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004895 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4896 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04004897 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004898 final String pkg = parentNotification.sbn.getPackageName();
4899 final int userId = parentNotification.getUserId();
4900 final int reason = REASON_GROUP_SUMMARY_CANCELED;
4901 for (int i = notificationList.size() - 1; i >= 0; i--) {
4902 final NotificationRecord childR = notificationList.get(i);
4903 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04004904 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004905 childR.getGroupKey().equals(parentNotification.getGroupKey())
Beverly40239d92017-07-07 10:20:41 -04004906 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
4907 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02004908 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4909 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04004910 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04004911 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04004912 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02004913 }
4914 }
4915 }
4916
Julia Reynolds88860ce2017-06-01 16:55:49 -04004917 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004918 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004919 {
The Android Open Source Project10592532009-03-18 17:39:46 -07004920 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05004921 NotificationRecord ledNotification = null;
4922 while (ledNotification == null && !mLights.isEmpty()) {
4923 final String owner = mLights.get(mLights.size() - 1);
4924 ledNotification = mNotificationsByKey.get(owner);
4925 if (ledNotification == null) {
4926 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4927 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004928 }
4929 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05004930
Mike Lockwood63b5ad92011-08-30 09:55:30 -04004931 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05004932 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05004933 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07004934 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004935 NotificationRecord.Light light = ledNotification.getLight();
4936 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05004937 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004938 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4939 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05004940 }
The Android Open Source Project10592532009-03-18 17:39:46 -07004941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004942 }
4943
Julia Reynolds88860ce2017-06-01 16:55:49 -04004944 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004945 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
4946 String groupKey, int userId) {
4947 List<NotificationRecord> records = new ArrayList<>();
4948 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
4949 records.addAll(
4950 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
4951 return records;
4952 }
4953
4954
Julia Reynolds88860ce2017-06-01 16:55:49 -04004955 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004956 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
4957 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
4958 List<NotificationRecord> records = new ArrayList<>();
4959 final int len = list.size();
4960 for (int i = 0; i < len; i++) {
4961 NotificationRecord r = list.get(i);
4962 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
4963 && r.sbn.getPackageName().equals(pkg)) {
4964 records.add(r);
4965 }
4966 }
4967 return records;
4968 }
4969
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004970 // Searches both enqueued and posted notifications by key.
4971 // TODO: need to combine a bunch of these getters with slightly different behavior.
4972 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04004973 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004974 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004975 NotificationRecord r;
4976 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4977 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004978 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004979 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4980 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004981 }
4982 return null;
4983 }
4984
Julia Reynolds88860ce2017-06-01 16:55:49 -04004985 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004986 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004987 NotificationRecord r;
4988 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4989 return r;
4990 }
4991 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4992 != null) {
4993 return r;
4994 }
4995 return null;
4996 }
4997
Julia Reynolds88860ce2017-06-01 16:55:49 -04004998 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004999 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005000 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005001 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005002 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005003 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01005004 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5005 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005006 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005007 }
5008 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005009 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005010 }
5011
Julia Reynolds88860ce2017-06-01 16:55:49 -04005012 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005013 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04005014 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005015 final int N = list.size();
5016 for (int i = 0; i < N; i++) {
5017 if (key.equals(list.get(i).getKey())) {
5018 return list.get(i);
5019 }
5020 }
5021 return null;
5022 }
5023
Julia Reynolds88860ce2017-06-01 16:55:49 -04005024 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02005025 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02005026 final int N = mNotificationList.size();
5027 for (int i = 0; i < N; i++) {
5028 if (key.equals(mNotificationList.get(i).getKey())) {
5029 return i;
5030 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02005031 }
Christoph Studerc5115552014-06-12 20:22:31 +02005032 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02005033 }
5034
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005035 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005036 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005037 updateLightsLocked();
5038 }
5039 }
John Spurlocke677d712014-02-13 12:52:19 -05005040
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005041 protected boolean isCallingUidSystem() {
5042 final int uid = Binder.getCallingUid();
5043 return uid == Process.SYSTEM_UID;
5044 }
5045
5046 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04005047 final int appid = UserHandle.getAppId(uid);
5048 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5049 }
John Spurlockb408e8e2014-04-23 21:12:45 -04005050
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005051 // TODO: Most calls should probably move to isCallerSystem.
5052 protected boolean isCallerSystemOrPhone() {
5053 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04005054 }
5055
Julia Reynoldsb852e562017-06-06 16:14:18 -04005056 private void checkCallerIsSystemOrShell() {
5057 if (Binder.getCallingUid() == Process.SHELL_UID) {
5058 return;
5059 }
5060 checkCallerIsSystem();
5061 }
5062
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005063 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005064 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005065 return;
5066 }
5067 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5068 }
5069
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005070 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005071 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005072 return;
5073 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04005074 checkCallerIsSameApp(pkg);
5075 }
5076
Chad Brubaker6b68f102017-01-27 13:39:00 -08005077 private boolean isCallerInstantApp(String pkg) {
5078 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005079 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08005080 return false;
5081 }
5082
5083 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5084
5085 try {
5086 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5087 UserHandle.getCallingUserId());
5088 if (ai == null) {
5089 throw new SecurityException("Unknown package " + pkg);
5090 }
5091 return ai.isInstantApp();
5092 } catch (RemoteException re) {
5093 throw new SecurityException("Unknown package " + pkg, re);
5094 }
5095
5096 }
5097
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005098 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04005099 final int uid = Binder.getCallingUid();
5100 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005101 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04005102 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04005103 if (ai == null) {
5104 throw new SecurityException("Unknown package " + pkg);
5105 }
John Spurlock7340fc82014-04-24 18:50:12 -04005106 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005107 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04005108 + pkg + " which is owned by uid " + ai.uid);
5109 }
5110 } catch (RemoteException re) {
5111 throw new SecurityException("Unknown package " + pkg + "\n" + re);
5112 }
5113 }
5114
John Spurlock32fe4c62014-10-02 12:16:02 -04005115 private static String callStateToString(int state) {
5116 switch (state) {
5117 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5118 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5119 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5120 default: return "CALL_STATE_UNKNOWN_" + state;
5121 }
5122 }
5123
5124 private void listenForCallState() {
5125 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5126 @Override
5127 public void onCallStateChanged(int state, String incomingNumber) {
5128 if (mCallState == state) return;
5129 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5130 mCallState = state;
5131 }
5132 }, PhoneStateListener.LISTEN_CALL_STATE);
5133 }
5134
Christoph Studer05ad4822014-05-16 14:16:03 +02005135 /**
5136 * Generates a NotificationRankingUpdate from 'sbns', considering only
5137 * notifications visible to the given listener.
5138 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005139 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005140 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04005141 final int N = mNotificationList.size();
5142 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02005143 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05005144 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04005145 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005146 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005147 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05005148 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005149 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05005150 Bundle overridePeople = new Bundle();
5151 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005152 Bundle showBadge = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04005153 for (int i = 0; i < N; i++) {
5154 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02005155 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005156 continue;
5157 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005158 final String key = record.sbn.getKey();
5159 keys.add(key);
5160 importance.add(record.getImportance());
5161 if (record.getImportanceExplanation() != null) {
5162 explanation.putCharSequence(key, record.getImportanceExplanation());
5163 }
Chris Wren333a61c2014-05-28 16:40:57 -04005164 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005165 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005166
Christoph Studer05ad4822014-05-16 14:16:03 +02005167 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005168 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005169 if (record.getPackageVisibilityOverride()
5170 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005171 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005172 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04005173 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05005174 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05005175 overridePeople.putStringArrayList(key, record.getPeopleOverride());
5176 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05005177 showBadge.putBoolean(key, record.canShowBadge());
Christoph Studer05ad4822014-05-16 14:16:03 +02005178 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005179 final int M = keys.size();
5180 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02005181 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05005182 int[] importanceAr = new int[M];
5183 for (int i = 0; i < M; i++) {
5184 importanceAr[i] = importance.get(i);
5185 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005186 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05005187 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Julia Reynolds924eed12017-01-19 09:52:07 -05005188 channels, overridePeople, snoozeCriteria, showBadge);
Christoph Studer05ad4822014-05-16 14:16:03 +02005189 }
5190
Julia Reynoldsda781472017-04-12 09:41:16 -04005191 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005192 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04005193 mCompanionManager = getCompanionManager();
5194 }
5195 // Companion mgr doesn't exist on all device types
5196 if (mCompanionManager == null) {
5197 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005198 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005199 long identity = Binder.clearCallingIdentity();
5200 try {
5201 List<String> associations = mCompanionManager.getAssociations(
5202 info.component.getPackageName(), info.userid);
5203 if (!ArrayUtils.isEmpty(associations)) {
5204 return true;
5205 }
5206 } catch (SecurityException se) {
5207 // Not a privileged listener
5208 } catch (RemoteException re) {
5209 Slog.e(TAG, "Cannot reach companion device service", re);
5210 } catch (Exception e) {
5211 Slog.e(TAG, "Cannot verify listener " + info, e);
5212 } finally {
5213 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005214 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005215 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005216 }
5217
Julia Reynolds727a7282017-04-13 10:54:01 -04005218 protected ICompanionDeviceManager getCompanionManager() {
5219 return ICompanionDeviceManager.Stub.asInterface(
5220 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5221 }
5222
Christoph Studercef37cf2014-07-25 14:18:17 +02005223 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5224 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5225 return false;
5226 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07005227 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02005228 return true;
5229 }
5230
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00005231 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005232 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005233 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005234 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005235 } catch (RemoteException re) {
5236 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00005237 } catch (IllegalArgumentException ex) {
5238 // Package not found.
5239 return false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005240 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005241 }
5242
Chris Wren47633422016-01-22 09:56:59 -05005243 private class TrimCache {
5244 StatusBarNotification heavy;
5245 StatusBarNotification sbnClone;
5246 StatusBarNotification sbnCloneLight;
5247
5248 TrimCache(StatusBarNotification sbn) {
5249 heavy = sbn;
5250 }
5251
5252 StatusBarNotification ForListener(ManagedServiceInfo info) {
5253 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5254 if (sbnCloneLight == null) {
5255 sbnCloneLight = heavy.cloneLight();
5256 }
5257 return sbnCloneLight;
5258 } else {
5259 if (sbnClone == null) {
5260 sbnClone = heavy.clone();
5261 }
5262 return sbnClone;
5263 }
5264 }
5265 }
5266
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005267 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005268 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05005269
Julia Reynoldsb852e562017-06-06 16:14:18 -04005270 public NotificationAssistants(IPackageManager pm) {
5271 super(getContext(), mNotificationLock, mUserProfiles, pm);
Chris Wren51017d02015-12-15 15:34:46 -05005272 }
5273
5274 @Override
5275 protected Config getConfig() {
5276 Config c = new Config();
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005277 c.caption = "notification assistant service";
5278 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005279 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005280 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5281 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05005282 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005283 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05005284 return c;
5285 }
5286
5287 @Override
5288 protected IInterface asInterface(IBinder binder) {
5289 return INotificationListener.Stub.asInterface(binder);
5290 }
5291
5292 @Override
5293 protected boolean checkType(IInterface service) {
5294 return service instanceof INotificationListener;
5295 }
5296
5297 @Override
5298 protected void onServiceAdded(ManagedServiceInfo info) {
5299 mListeners.registerGuestService(info);
5300 }
5301
5302 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005303 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05005304 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5305 mListeners.unregisterService(removed.service, removed.userid);
5306 }
Chris Wren47633422016-01-22 09:56:59 -05005307
5308 public void onNotificationEnqueued(final NotificationRecord r) {
5309 final StatusBarNotification sbn = r.sbn;
5310 TrimCache trimCache = new TrimCache(sbn);
5311
Chris Wren47633422016-01-22 09:56:59 -05005312 // There should be only one, but it's a list, so while we enforce
5313 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04005314 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05005315 boolean sbnVisible = isVisibleToListener(sbn, info);
5316 if (!sbnVisible) {
5317 continue;
5318 }
5319
5320 final int importance = r.getImportance();
5321 final boolean fromUser = r.isImportanceFromUser();
5322 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005323 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05005324 @Override
5325 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005326 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05005327 }
5328 });
5329 }
5330 }
5331
5332 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005333 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005334 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05005335 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5336 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005337 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05005338 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005339 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05005340 }
5341 }
5342
Julia Reynolds79672302017-01-12 08:30:16 -05005343 /**
5344 * asynchronously notify the assistant that a notification has been snoozed until a
5345 * context
5346 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005347 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05005348 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5349 final String snoozeCriterionId) {
5350 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04005351 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds79672302017-01-12 08:30:16 -05005352 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5353 mHandler.post(new Runnable() {
5354 @Override
5355 public void run() {
5356 final INotificationListener assistant =
5357 (INotificationListener) info.service;
5358 StatusBarNotificationHolder sbnHolder
5359 = new StatusBarNotificationHolder(sbnToPost);
5360 try {
5361 assistant.onNotificationSnoozedUntilContext(
5362 sbnHolder, snoozeCriterionId);
5363 } catch (RemoteException ex) {
5364 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5365 }
5366 }
5367 });
5368 }
5369 }
5370
Chris Wren47633422016-01-22 09:56:59 -05005371 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04005372 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05005373 }
Chris Wren51017d02015-12-15 15:34:46 -05005374 }
5375
John Spurlock7340fc82014-04-24 18:50:12 -04005376 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005377 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04005378
Christoph Studerb82bc782014-08-20 14:29:43 +02005379 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5380
Julia Reynoldsb852e562017-06-06 16:14:18 -04005381 public NotificationListeners(IPackageManager pm) {
5382 super(getContext(), mNotificationLock, mUserProfiles, pm);
5383
John Spurlock7340fc82014-04-24 18:50:12 -04005384 }
5385
5386 @Override
5387 protected Config getConfig() {
5388 Config c = new Config();
5389 c.caption = "notification listener";
5390 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005391 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04005392 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5393 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5394 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5395 c.clientLabel = R.string.notification_listener_binding_label;
5396 return c;
5397 }
5398
5399 @Override
5400 protected IInterface asInterface(IBinder binder) {
5401 return INotificationListener.Stub.asInterface(binder);
5402 }
5403
5404 @Override
Chris Wren51017d02015-12-15 15:34:46 -05005405 protected boolean checkType(IInterface service) {
5406 return service instanceof INotificationListener;
5407 }
5408
5409 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04005410 public void onServiceAdded(ManagedServiceInfo info) {
5411 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04005412 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005413 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04005414 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005415 }
John Spurlock7340fc82014-04-24 18:50:12 -04005416 try {
Chris Wren333a61c2014-05-28 16:40:57 -04005417 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04005418 } catch (RemoteException e) {
5419 // we tried
5420 }
5421 }
5422
John Spurlock1fa865f2014-07-21 14:56:39 -04005423 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005424 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04005425 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07005426 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005427 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01005428 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04005429 }
Christoph Studerb82bc782014-08-20 14:29:43 +02005430 mLightTrimListeners.remove(removed);
5431 }
5432
Julia Reynolds88860ce2017-06-01 16:55:49 -04005433 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02005434 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5435 if (trim == TRIM_LIGHT) {
5436 mLightTrimListeners.add(info);
5437 } else {
5438 mLightTrimListeners.remove(info);
5439 }
5440 }
5441
5442 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5443 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04005444 }
5445
John Spurlock7340fc82014-04-24 18:50:12 -04005446 /**
5447 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02005448 *
5449 * <p>
5450 * Also takes care of removing a notification that has been visible to a listener before,
5451 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04005452 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005453 @GuardedBy("mNotificationLock")
Christoph Studercef37cf2014-07-25 14:18:17 +02005454 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
Christoph Studerb82bc782014-08-20 14:29:43 +02005455 // Lazily initialized snapshots of the notification.
Chris Wren47633422016-01-22 09:56:59 -05005456 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02005457
Julia Reynolds00314d92017-04-14 10:01:24 -04005458 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005459 boolean sbnVisible = isVisibleToListener(sbn, info);
5460 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5461 // This notification hasn't been and still isn't visible -> ignore.
5462 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005463 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005464 }
Chris Wren333a61c2014-05-28 16:40:57 -04005465 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02005466
5467 // This notification became invisible -> remove the old one.
5468 if (oldSbnVisible && !sbnVisible) {
5469 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5470 mHandler.post(new Runnable() {
5471 @Override
5472 public void run() {
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005473 notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02005474 }
5475 });
Christoph Studer05ad4822014-05-16 14:16:03 +02005476 continue;
5477 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005478
Chris Wren47633422016-01-22 09:56:59 -05005479 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005480 mHandler.post(new Runnable() {
5481 @Override
5482 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02005483 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02005484 }
5485 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005486 }
5487 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005488
John Spurlock7340fc82014-04-24 18:50:12 -04005489 /**
5490 * asynchronously notify all listeners about a removed notification
5491 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005492 @GuardedBy("mNotificationLock")
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005493 public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04005494 // make a copy in case changes are made to the underlying Notification object
5495 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5496 // notification
5497 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04005498 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005499 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005500 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005501 }
Chris Wren333a61c2014-05-28 16:40:57 -04005502 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005503 mHandler.post(new Runnable() {
5504 @Override
5505 public void run() {
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005506 notifyRemoved(info, sbnLight, update, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02005507 }
5508 });
Chris Wrenf9536642014-04-17 10:01:54 -04005509 }
5510 }
5511
5512 /**
5513 * asynchronously notify all listeners about a reordering of notifications
Chris Wrenf9536642014-04-17 10:01:54 -04005514 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005515 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005516 public void notifyRankingUpdateLocked() {
Julia Reynolds00314d92017-04-14 10:01:24 -04005517 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005518 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5519 continue;
5520 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005521 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
John Spurlock7340fc82014-04-24 18:50:12 -04005522 mHandler.post(new Runnable() {
5523 @Override
5524 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -04005525 notifyRankingUpdate(serviceInfo, update);
John Spurlock7340fc82014-04-24 18:50:12 -04005526 }
5527 });
Kenny Guya263e4e2014-03-03 18:24:03 +00005528 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005529 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005530
Julia Reynolds88860ce2017-06-01 16:55:49 -04005531 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04005532 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005533 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04005534 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5535 continue;
5536 }
5537 mHandler.post(new Runnable() {
5538 @Override
5539 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005540 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005541 }
5542 });
5543 }
5544 }
5545
Christoph Studer85a384b2014-08-27 20:16:15 +02005546 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005547 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005548 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5549 continue;
5550 }
5551 mHandler.post(new Runnable() {
5552 @Override
5553 public void run() {
5554 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5555 }
5556 });
5557 }
5558 }
5559
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005560 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005561 final NotificationChannel channel, final int modificationType) {
5562 if (channel == null) {
5563 return;
5564 }
5565 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04005566 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005567 continue;
5568 }
Julia Reynolds018aa622017-04-20 11:31:30 -04005569
Julia Reynoldsda781472017-04-12 09:41:16 -04005570 mHandler.post(new Runnable() {
5571 @Override
5572 public void run() {
Julia Reynolds018aa622017-04-20 11:31:30 -04005573 if (hasCompanionDevice(serviceInfo)) {
5574 notifyNotificationChannelChanged(
5575 serviceInfo, pkg, user, channel, modificationType);
5576 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005577 }
5578 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005579 }
5580 }
5581
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005582 protected void notifyNotificationChannelGroupChanged(
5583 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5584 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005585 if (group == null) {
5586 return;
5587 }
5588 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04005589 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005590 continue;
5591 }
Julia Reynolds018aa622017-04-20 11:31:30 -04005592
Julia Reynoldsda781472017-04-12 09:41:16 -04005593 mHandler.post(new Runnable() {
5594 @Override
5595 public void run() {
Julia Reynolds018aa622017-04-20 11:31:30 -04005596 if (hasCompanionDevice(serviceInfo)) {
5597 notifyNotificationChannelGroupChanged(
5598 serviceInfo, pkg, user, group, modificationType);
5599 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005600 }
5601 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005602 }
5603 }
5604
Christoph Studercef37cf2014-07-25 14:18:17 +02005605 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02005606 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04005607 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005608 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04005609 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07005610 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04005611 } catch (RemoteException ex) {
5612 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5613 }
5614 }
5615
Christoph Studercef37cf2014-07-25 14:18:17 +02005616 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005617 NotificationRankingUpdate rankingUpdate, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04005618 if (!info.enabledAndUserMatches(sbn.getUserId())) {
5619 return;
5620 }
Christoph Studer05ad4822014-05-16 14:16:03 +02005621 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005622 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04005623 try {
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005624 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04005625 } catch (RemoteException ex) {
5626 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04005627 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005628 }
Chris Wrenf9536642014-04-17 10:01:54 -04005629
Christoph Studer05ad4822014-05-16 14:16:03 +02005630 private void notifyRankingUpdate(ManagedServiceInfo info,
5631 NotificationRankingUpdate rankingUpdate) {
5632 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04005633 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02005634 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04005635 } catch (RemoteException ex) {
5636 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5637 }
5638 }
John Spurlock1fa865f2014-07-21 14:56:39 -04005639
John Spurlockd8afe3c2014-08-01 14:04:07 -04005640 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04005641 final INotificationListener listener = (INotificationListener) info.service;
5642 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005643 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005644 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005645 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04005646 }
5647 }
Justin Koh38156c52014-06-04 13:57:49 -07005648
Christoph Studer85a384b2014-08-27 20:16:15 +02005649 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5650 int interruptionFilter) {
5651 final INotificationListener listener = (INotificationListener) info.service;
5652 try {
5653 listener.onInterruptionFilterChanged(interruptionFilter);
5654 } catch (RemoteException ex) {
5655 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5656 }
5657 }
5658
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005659 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005660 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005661 final int modificationType) {
5662 final INotificationListener listener = (INotificationListener) info.service;
5663 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005664 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005665 } catch (RemoteException ex) {
5666 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5667 }
5668 }
5669
5670 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005671 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005672 final int modificationType) {
5673 final INotificationListener listener = (INotificationListener) info.service;
5674 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005675 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005676 } catch (RemoteException ex) {
5677 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5678 }
5679 }
5680
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005681 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07005682 if (packageName == null) {
5683 return false;
5684 }
5685 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005686 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005687 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07005688 if (packageName.equals(serviceInfo.component.getPackageName())) {
5689 return true;
5690 }
5691 }
5692 }
5693 return false;
5694 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005695 }
John Spurlock25e2d242014-06-27 13:58:23 -04005696
5697 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04005698 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04005699 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04005700 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04005701 public long since;
5702 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04005703 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05005704 public boolean proto = false;
John Spurlock25e2d242014-06-27 13:58:23 -04005705
5706 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04005707 final DumpFilter filter = new DumpFilter();
5708 for (int ai = 0; ai < args.length; ai++) {
5709 final String a = args[ai];
Julia Reynoldsc9842c12017-02-07 12:46:41 -05005710 if ("--proto".equals(args[0])) {
5711 filter.proto = true;
5712 }
Dan Sandlera1770312015-07-10 13:59:29 -04005713 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5714 filter.redact = false;
5715 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5716 if (ai < args.length-1) {
5717 ai++;
5718 filter.pkgFilter = args[ai].trim().toLowerCase();
5719 if (filter.pkgFilter.isEmpty()) {
5720 filter.pkgFilter = null;
5721 } else {
5722 filter.filtered = true;
5723 }
5724 }
5725 } else if ("--zen".equals(a) || "zen".equals(a)) {
5726 filter.filtered = true;
5727 filter.zen = true;
5728 } else if ("--stats".equals(a)) {
5729 filter.stats = true;
5730 if (ai < args.length-1) {
5731 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01005732 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04005733 } else {
5734 filter.since = 0;
5735 }
5736 }
John Spurlock25e2d242014-06-27 13:58:23 -04005737 }
Dan Sandlera1770312015-07-10 13:59:29 -04005738 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04005739 }
5740
5741 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04005742 if (!filtered) return true;
5743 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04005744 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04005745 }
5746
5747 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04005748 if (!filtered) return true;
5749 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04005750 }
5751
5752 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04005753 if (!filtered) return true;
5754 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04005755 }
5756
5757 @Override
5758 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04005759 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04005760 }
5761 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07005762
5763 /**
5764 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5765 * binder without sending large amounts of data over a oneway transaction.
5766 */
5767 private static final class StatusBarNotificationHolder
5768 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07005769 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005770
5771 public StatusBarNotificationHolder(StatusBarNotification value) {
5772 mValue = value;
5773 }
5774
Griff Hazene9aac5f2014-09-05 20:04:09 -07005775 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07005776 @Override
5777 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07005778 StatusBarNotification value = mValue;
5779 mValue = null;
5780 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005781 }
5782 }
John Spurlock7c74f782015-06-04 13:01:42 -04005783
Julia Reynoldsb852e562017-06-06 16:14:18 -04005784 private class ShellCmd extends ShellCommand {
5785 public static final String USAGE = "help\n"
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005786 + "allow_listener COMPONENT\n"
5787 + "disallow_listener COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005788 + "set_assistant COMPONENT\n"
5789 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04005790 + "allow_dnd PACKAGE\n"
5791 + "disallow_dnd PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04005792
Julia Reynoldsb852e562017-06-06 16:14:18 -04005793 @Override
5794 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07005795 if (cmd == null) {
5796 return handleDefaultCommands(cmd);
5797 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005798 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04005799 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005800 switch (cmd) {
5801 case "allow_dnd": {
5802 getBinderService().setNotificationPolicyAccessGranted(
5803 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04005804 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04005805 break;
5806
5807 case "disallow_dnd": {
5808 getBinderService().setNotificationPolicyAccessGranted(
5809 getNextArgRequired(), false);
5810 }
5811 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005812 case "allow_listener": {
5813 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5814 if (cn == null) {
5815 pw.println("Invalid listener - must be a ComponentName");
5816 return -1;
5817 }
5818 getBinderService().setNotificationListenerAccessGranted(cn, true);
5819 }
5820 break;
5821 case "disallow_listener": {
5822 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5823 if (cn == null) {
5824 pw.println("Invalid listener - must be a ComponentName");
5825 return -1;
5826 }
5827 getBinderService().setNotificationListenerAccessGranted(cn, false);
5828 }
5829 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005830 case "allow_assistant": {
5831 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5832 if (cn == null) {
5833 pw.println("Invalid assistant - must be a ComponentName");
5834 return -1;
5835 }
5836 getBinderService().setNotificationAssistantAccessGranted(cn, true);
5837 }
5838 break;
5839 case "disallow_assistant": {
5840 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5841 if (cn == null) {
5842 pw.println("Invalid assistant - must be a ComponentName");
5843 return -1;
5844 }
5845 getBinderService().setNotificationAssistantAccessGranted(cn, false);
5846 }
5847 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04005848
5849 default:
5850 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04005851 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005852 } catch (Exception e) {
5853 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04005854 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04005855 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04005856 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04005857 }
5858
Julia Reynoldsb852e562017-06-06 16:14:18 -04005859 @Override
5860 public void onHelp() {
5861 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04005862 }
5863 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005864}