blob: f60d92340492a9b2a96b99897cfc7d8259633e80 [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;
Sailesh Nepale8bde702017-07-21 11:44:04 -0700138import android.telecom.TelecomManager;
John Spurlock32fe4c62014-10-02 12:16:02 -0400139import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500140import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700141import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400142import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400143import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700144import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800146import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700147import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400148import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500149import android.util.proto.ProtoOutputStream;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700150import android.view.WindowManagerInternal;
svetoslavganov75986cf2009-05-14 22:28:01 -0700151import android.view.accessibility.AccessibilityEvent;
152import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000154
Scott Greenwald9a05b312013-06-28 00:37:54 -0400155import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400156import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400157import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500158import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500159import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500160import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Chris Wrend1dbc922015-06-19 17:51:16 -0400161import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400162import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600163import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400164import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400165import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400166import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700167import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800168import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700169import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800170import com.android.server.SystemService;
171import com.android.server.lights.Light;
172import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400173import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700174import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400175import com.android.server.statusbar.StatusBarManagerInternal;
Ruben Brunke24b9a62016-02-16 21:38:24 -0800176import com.android.server.notification.ManagedServices.UserProfiles;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800177
John Spurlockb408e8e2014-04-23 21:12:45 -0400178import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000179
Chris Wrene4b38802015-07-07 15:54:19 -0400180import org.json.JSONException;
181import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700182import org.xmlpull.v1.XmlPullParser;
183import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400184import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700185
John Spurlock35ef0a62015-05-28 11:24:10 -0400186import java.io.ByteArrayInputStream;
187import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400188import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400190import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400191import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400192import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400193import java.io.InputStream;
194import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195import java.io.PrintWriter;
Beverly5d463b62017-07-26 14:13:40 -0400196import java.net.URI;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100197import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500198import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000200import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500201import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400202import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200203import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500204import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400205import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500206import java.util.concurrent.TimeUnit;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400207
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400208/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800209public class NotificationManagerService extends SystemService {
210 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100211 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800212 public static final boolean ENABLE_CHILD_NOTIFICATIONS
213 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
Adam Lesinski182f73f2013-12-05 16:48:06 -0800215 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400216 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 // message codes
Adam Lesinski182f73f2013-12-05 16:48:06 -0800219 static final int MESSAGE_TIMEOUT = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400220 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500221 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
222 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
223 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
224
225 // ranking thread messages
226 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
227 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700229 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800230 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800231
Adam Lesinski182f73f2013-12-05 16:48:06 -0800232 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200233
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500234 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
235
Adam Lesinski182f73f2013-12-05 16:48:06 -0800236 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237
Adam Lesinski182f73f2013-12-05 16:48:06 -0800238 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500239
Adam Lesinski182f73f2013-12-05 16:48:06 -0800240 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400241
Christoph Studer12aeda82014-09-23 19:08:56 +0200242 // When #matchesCallFilter is called from the ringer, wait at most
243 // 3s to resolve the contacts. This timeout is required since
244 // ContactsProvider might take a long time to start up.
245 //
246 // Return STARRED_CONTACT when the timeout is hit in order to avoid
247 // missed calls in ZEN mode "Important".
248 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
249 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
250 ValidateNotificationPeople.STARRED_CONTACT;
251
Christoph Studer265c1052014-07-23 17:14:33 +0200252 /** notification_enqueue status value for a newly enqueued notification. */
253 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
254
255 /** notification_enqueue status value for an existing notification. */
256 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
257
258 /** notification_enqueue status value for an ignored notification. */
259 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400260 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200261
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500262 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
263
Julia Reynolds2a128742016-11-28 14:29:25 -0500264 private static final String ACTION_NOTIFICATION_TIMEOUT =
265 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
266 private static final int REQUEST_CODE_TIMEOUT = 1;
267 private static final String SCHEME_TIMEOUT = "timeout";
268 private static final String EXTRA_KEY = "key";
269
Adam Lesinski182f73f2013-12-05 16:48:06 -0800270 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400271 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500272 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500273 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800274 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500275 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800276 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800277 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700278 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500279 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400280 private ICompanionDeviceManager mCompanionManager;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400283 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400284 private final HandlerThread mRankingThread = new HandlerThread("ranker",
285 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286
Adam Lesinski182f73f2013-12-05 16:48:06 -0800287 private Light mNotificationLight;
288 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800289
Daniel Sandleredbb3802012-11-13 20:49:47 -0800290 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400291 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800292 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800293
John Spurlockd8afe3c2014-08-01 14:04:07 -0400294 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400295 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500296 private String mSoundNotificationKey;
297 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298
Bryce Lee7219ada2016-04-08 10:54:23 -0700299 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400300 new SparseArray<>();
301 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400302 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500303 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400304
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500305 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400306 private boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400307 protected boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500308 private boolean mNotificationPulseEnabled;
309
Beverly5d463b62017-07-26 14:13:40 -0400310 private Uri mInCallNotificationUri;
311 private AudioAttributes mInCallNotificationAudioAttributes;
312 private float mInCallNotificationVolume;
Marta Białka39c992f2011-03-10 10:27:24 +0100313
Daniel Sandler09a247e2013-02-14 10:24:17 -0500314 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500315 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400316 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400317 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400318 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400319 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400320 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500321 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400322 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400323 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400324 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200325 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326
Chris Wren6054e612014-11-25 17:16:46 -0500327 // The last key in this list owns the hardware.
328 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700329
Adam Lesinski182f73f2013-12-05 16:48:06 -0800330 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700331 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500332
Griff Hazen9f637d12014-06-10 11:13:51 -0700333 private Archive mArchive;
334
John Spurlock21258a32015-05-27 18:22:55 -0400335 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400336 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400337
Daniel Sandler0da673f2012-04-11 12:33:16 -0400338 private static final int DB_VERSION = 1;
339
John Spurlock21258a32015-05-27 18:22:55 -0400340 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400341 private static final String ATTR_VERSION = "version";
342
Chris Wren54bbef42014-07-09 18:37:56 -0400343 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400344
John Spurlockb408e8e2014-04-23 21:12:45 -0400345 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400346 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400347 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400348 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200349 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100350
John Spurlocke6a7d932014-03-13 12:29:00 -0400351 private static final int MY_UID = Process.myUid();
352 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700353 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500354 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400355 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400356 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400357
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400358 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400359 private GroupHelper mGroupHelper;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500360 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400361
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500362 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700363 final int mBufferSize;
364 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500365
Griff Hazen9f637d12014-06-10 11:13:51 -0700366 public Archive(int size) {
367 mBufferSize = size;
368 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500369 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700370
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400371 public String toString() {
372 final StringBuilder sb = new StringBuilder();
373 final int N = mBuffer.size();
374 sb.append("Archive (");
375 sb.append(N);
376 sb.append(" notification");
377 sb.append((N==1)?")":"s)");
378 return sb.toString();
379 }
380
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500381 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700382 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500383 mBuffer.removeFirst();
384 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400385
386 // We don't want to store the heavy bits of the notification in the archive,
387 // but other clients in the system process might be using the object, so we
388 // store a (lightened) copy.
389 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500390 }
391
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500392 public Iterator<StatusBarNotification> descendingIterator() {
393 return mBuffer.descendingIterator();
394 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500395
396 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700397 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500398 final StatusBarNotification[] a
399 = new StatusBarNotification[Math.min(count, mBuffer.size())];
400 Iterator<StatusBarNotification> iter = descendingIterator();
401 int i=0;
402 while (iter.hasNext() && i < count) {
403 a[i++] = iter.next();
404 }
405 return a;
406 }
407
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500408 }
409
Julia Reynolds88a879f2017-07-26 17:06:46 -0400410 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400411 String defaultListenerAccess = getContext().getResources().getString(
412 com.android.internal.R.string.config_defaultListenerAccessPackages);
413 if (defaultListenerAccess != null) {
414 for (String whitelisted :
415 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
416 // Gather all notification listener components for candidate pkgs.
417 Set<ComponentName> approvedListeners =
418 mListeners.queryPackageForServices(whitelisted,
419 PackageManager.MATCH_DIRECT_BOOT_AWARE
420 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
421 for (ComponentName cn : approvedListeners) {
422 try {
423 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
424 userId, true);
425 } catch (RemoteException e) {
426 e.printStackTrace();
427 }
428 }
429 }
430 }
431 String defaultDndAccess = getContext().getResources().getString(
432 com.android.internal.R.string.config_defaultDndAccessPackages);
433 if (defaultListenerAccess != null) {
434 for (String whitelisted :
435 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
436 try {
437 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
438 } catch (RemoteException e) {
439 e.printStackTrace();
440 }
441 }
442 }
443 }
444
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400445 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400446 throws XmlPullParserException, NumberFormatException, IOException {
447 final XmlPullParser parser = Xml.newPullParser();
448 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400449 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
450 boolean migratedManagedServices = false;
451 int outerDepth = parser.getDepth();
452 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
453 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
454 mZenModeHelper.readXml(parser, forRestore);
455 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
456 mRankingHelper.readXml(parser, forRestore);
457 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400458 // No non-system managed services are allowed on low ram devices
459 if (!ActivityManager.isLowRamDeviceStatic()) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400460 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
461 mListeners.readXml(parser);
462 migratedManagedServices = true;
463 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
464 mAssistants.readXml(parser);
465 migratedManagedServices = true;
466 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
467 mConditionProviders.readXml(parser);
468 migratedManagedServices = true;
469 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400470 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400471 }
472
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400473 if (!migratedManagedServices) {
474 mListeners.migrateToXml();
475 mAssistants.migrateToXml();
476 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400477 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400478 }
479 }
480
John Spurlock056c5192014-04-20 21:52:01 -0400481 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400482 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500483 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400484
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400485 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400486 try {
487 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400488 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400489 } catch (FileNotFoundException e) {
490 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400491 // Load default managed services approvals
Julia Reynolds88a879f2017-07-26 17:06:46 -0400492 readDefaultApprovedServices(UserHandle.USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400493 } catch (IOException e) {
494 Log.wtf(TAG, "Unable to read notification policy", e);
495 } catch (NumberFormatException e) {
496 Log.wtf(TAG, "Unable to parse notification policy", e);
497 } catch (XmlPullParserException e) {
498 Log.wtf(TAG, "Unable to parse notification policy", e);
499 } finally {
500 IoUtils.closeQuietly(infile);
501 }
502 }
503 }
504
505 public void savePolicyFile() {
506 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
507 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
508 }
509
510 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400511 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400512 synchronized (mPolicyFile) {
513 final FileOutputStream stream;
514 try {
515 stream = mPolicyFile.startWrite();
516 } catch (IOException e) {
517 Slog.w(TAG, "Failed to save policy file", e);
518 return;
519 }
520
521 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400522 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400523 mPolicyFile.finishWrite(stream);
524 } catch (IOException e) {
525 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
526 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400527 }
528 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400529 BackupManager.dataChanged(getContext().getPackageName());
530 }
531
532 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
533 final XmlSerializer out = new FastXmlSerializer();
534 out.setOutput(stream, StandardCharsets.UTF_8.name());
535 out.startDocument(null, true);
536 out.startTag(null, TAG_NOTIFICATION_POLICY);
537 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
538 mZenModeHelper.writeXml(out, forBackup);
539 mRankingHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400540 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400541 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400542 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400543 out.endTag(null, TAG_NOTIFICATION_POLICY);
544 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400545 }
546
Chris Wren66189fc2015-06-25 14:04:33 -0400547 /** Use this to check if a package can post a notification or toast. */
548 private boolean checkNotificationOp(String pkg, int uid) {
549 return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
Andrei Stingaceanu355b2322016-02-12 16:43:51 +0000550 == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
Chris Wren66189fc2015-06-25 14:04:33 -0400551 }
552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 private static final class ToastRecord
554 {
555 final int pid;
556 final String pkg;
Beverly4ee785b2017-08-11 12:49:56 -0400557 ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700559 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700561 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
562 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 this.pid = pid;
564 this.pkg = pkg;
565 this.callback = callback;
566 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700567 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 }
569
570 void update(int duration) {
571 this.duration = duration;
572 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800573
Beverly4ee785b2017-08-11 12:49:56 -0400574 void update(ITransientNotification callback) {
575 this.callback = callback;
576 }
577
John Spurlock25e2d242014-06-27 13:58:23 -0400578 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
579 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 pw.println(prefix + this);
581 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 @Override
584 public final String toString()
585 {
586 return "ToastRecord{"
587 + Integer.toHexString(System.identityHashCode(this))
588 + " pkg=" + pkg
589 + " callback=" + callback
590 + " duration=" + duration;
591 }
592 }
593
Beverly40239d92017-07-07 10:20:41 -0400594 @VisibleForTesting
595 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596
Adam Lesinski182f73f2013-12-05 16:48:06 -0800597 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500599 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400600 mDisableNotificationEffects =
601 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400602 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 // cancel whatever's going on
604 long identity = Binder.clearCallingIdentity();
605 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800606 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700607 if (player != null) {
608 player.stopAsync();
609 }
610 } catch (RemoteException e) {
611 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 Binder.restoreCallingIdentity(identity);
613 }
614
615 identity = Binder.clearCallingIdentity();
616 try {
617 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700618 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 Binder.restoreCallingIdentity(identity);
620 }
621 }
622 }
623 }
624
Adam Lesinski182f73f2013-12-05 16:48:06 -0800625 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400626 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500627 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400628 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000629 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 }
632
Adam Lesinski182f73f2013-12-05 16:48:06 -0800633 @Override
Christoph Studer03b87a22014-04-30 17:33:27 +0200634 public void onNotificationClick(int callingUid, int callingPid, String key) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500635 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200636 NotificationRecord r = mNotificationsByKey.get(key);
637 if (r == null) {
638 Log.w(TAG, "No notification with key: " + key);
639 return;
640 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400641 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500642 MetricsLogger.action(r.getLogMaker(now)
643 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
644 .setType(MetricsEvent.TYPE_ACTION));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400645 EventLogTags.writeNotificationClicked(key,
646 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
647
Christoph Studer03b87a22014-04-30 17:33:27 +0200648 StatusBarNotification sbn = r.sbn;
649 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
650 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
651 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400652 REASON_CLICK, null);
Christoph Studer03b87a22014-04-30 17:33:27 +0200653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 }
655
Adam Lesinski182f73f2013-12-05 16:48:06 -0800656 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200657 public void onNotificationActionClick(int callingUid, int callingPid, String key,
658 int actionIndex) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500659 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200660 NotificationRecord r = mNotificationsByKey.get(key);
661 if (r == null) {
662 Log.w(TAG, "No notification with key: " + key);
663 return;
664 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400665 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500666 MetricsLogger.action(r.getLogMaker(now)
667 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
668 .setType(MetricsEvent.TYPE_ACTION)
669 .setSubtype(actionIndex));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400670 EventLogTags.writeNotificationActionClicked(key, actionIndex,
671 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Christoph Studer4da84cd2014-10-21 17:24:20 +0200672 // TODO: Log action click via UsageStats.
673 }
674 }
675
676 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400677 public void onNotificationClear(int callingUid, int callingPid,
678 String pkg, String tag, int id, int userId) {
679 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000680 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400681 true, userId, REASON_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400682 }
683
Adam Lesinski182f73f2013-12-05 16:48:06 -0800684 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400685 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500686 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400687 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400688 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100689 if (clearEffects) {
690 clearEffects();
691 }
692 }
693
694 @Override
695 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500696 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100697 EventLogTags.writeNotificationPanelHidden();
698 }
699
700 @Override
701 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500702 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100703 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400704 clearSoundLocked();
705 clearVibrateLocked();
706 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 }
708 }
Joe Onorato005847b2010-06-04 16:08:02 -0400709
Adam Lesinski182f73f2013-12-05 16:48:06 -0800710 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400711 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000712 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400713 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
714 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400715 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400716 REASON_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700717 long ident = Binder.clearCallingIdentity();
718 try {
Christopher Tate8aa8fe12017-01-20 17:50:32 -0800719 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700720 "Bad notification posted from package " + pkg
721 + ": " + message);
722 } catch (RemoteException e) {
723 }
724 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400725 }
John Spurlocke677d712014-02-13 12:52:19 -0500726
727 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400728 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
729 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500730 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400731 for (NotificationVisibility nv : newlyVisibleKeys) {
732 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200733 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400734 r.setVisibility(true, nv.rank);
735 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200736 }
737 // Note that we might receive this event after notifications
738 // have already left the system, e.g. after dismissing from the
739 // shade. Hence not finding notifications in
740 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400741 for (NotificationVisibility nv : noLongerVisibleKeys) {
742 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200743 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400744 r.setVisibility(false, nv.rank);
745 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200746 }
747 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200748 }
Chris Wren78403d72014-07-28 10:23:24 +0100749
750 @Override
751 public void onNotificationExpansionChanged(String key,
752 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500753 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100754 NotificationRecord r = mNotificationsByKey.get(key);
755 if (r != null) {
756 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400757 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500758 MetricsLogger.action(r.getLogMaker(now)
759 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
760 .setType(MetricsEvent.TYPE_DETAIL));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400761 EventLogTags.writeNotificationExpansion(key,
762 userAction ? 1 : 0, expanded ? 1 : 0,
763 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100764 }
765 }
766 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 };
768
Julia Reynolds88860ce2017-06-01 16:55:49 -0400769 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400770 private void clearSoundLocked() {
771 mSoundNotificationKey = null;
772 long identity = Binder.clearCallingIdentity();
773 try {
774 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
775 if (player != null) {
776 player.stopAsync();
777 }
778 } catch (RemoteException e) {
779 } finally {
780 Binder.restoreCallingIdentity(identity);
781 }
782 }
783
Julia Reynolds88860ce2017-06-01 16:55:49 -0400784 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400785 private void clearVibrateLocked() {
786 mVibrateNotificationKey = null;
787 long identity = Binder.clearCallingIdentity();
788 try {
789 mVibrator.cancel();
790 } finally {
791 Binder.restoreCallingIdentity(identity);
792 }
793 }
794
Julia Reynolds88860ce2017-06-01 16:55:49 -0400795 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400796 private void clearLightsLocked() {
797 // light
798 mLights.clear();
799 updateLightsLocked();
800 }
801
Beverlyd4f96492017-08-02 13:36:11 -0400802 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
803 @Override
804 public void onReceive(Context context, Intent intent) {
805 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
806 mZenModeHelper.updateDefaultZenRules();
Julia Reynolds816797a2017-08-11 15:47:09 -0400807 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400808 }
809 }
810 };
811
Julia Reynoldsb852e562017-06-06 16:14:18 -0400812 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
813 @Override
814 public void onReceive(Context context, Intent intent) {
815 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
816 try {
817 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
818 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100819 int restoredFromSdkInt = intent.getIntExtra(
820 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400821 mListeners.onSettingRestored(
822 element, newValue, restoredFromSdkInt, getSendingUserId());
823 mConditionProviders.onSettingRestored(
824 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400825 } catch (Exception e) {
826 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
827 }
828 }
829 }
830 };
831
Julia Reynolds2a128742016-11-28 14:29:25 -0500832 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
833 @Override
834 public void onReceive(Context context, Intent intent) {
835 String action = intent.getAction();
836 if (action == null) {
837 return;
838 }
839 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
840 final NotificationRecord record;
841 synchronized (mNotificationLock) {
842 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
843 }
844 if (record != null) {
845 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
846 record.sbn.getPackageName(), record.sbn.getTag(),
847 record.sbn.getId(), 0,
848 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
849 REASON_TIMEOUT, null);
850 }
851 }
852 }
853 };
854
Kenny Guy70058402014-10-28 20:45:06 +0000855 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 @Override
857 public void onReceive(Context context, Intent intent) {
858 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -0800859 if (action == null) {
860 return;
861 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800863 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -0400864 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -0400865 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -0400866 boolean cancelNotifications = true;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000867 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -0400868
Chris Wren3da73022013-05-10 14:41:21 -0400869 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -0400870 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800871 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -0400872 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800873 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000874 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
875 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +0000876 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
877 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800878 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500879 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -0400880 boolean removingPackage = queryRemove &&
881 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
882 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800883 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800884 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500885 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000886 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
887 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
888 reason = REASON_PACKAGE_SUSPENDED;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800889 } else if (queryRestart) {
890 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500891 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800892 } else {
893 Uri uri = intent.getData();
894 if (uri == null) {
895 return;
896 }
897 String pkgName = uri.getSchemeSpecificPart();
898 if (pkgName == null) {
899 return;
900 }
Daniel Sandler26ece572012-06-01 15:38:46 -0400901 if (packageChanged) {
902 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -0700903 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500904 final int enabled = mPackageManager.getApplicationEnabledSetting(
905 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +0000906 changeUserId != UserHandle.USER_ALL ? changeUserId :
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500907 UserHandle.USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -0700908 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
909 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
910 cancelNotifications = false;
911 }
912 } catch (IllegalArgumentException e) {
913 // Package doesn't exist; probably racing with uninstall.
914 // cancelNotifications is already true, so nothing to do here.
915 if (DBG) {
916 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
917 }
Kenny Guy70058402014-10-28 20:45:06 +0000918 } catch (RemoteException e) {
919 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -0400920 }
921 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800922 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500923 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800925 if (pkgList != null && (pkgList.length > 0)) {
926 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -0400927 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400928 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
929 !queryRestart, changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -0400930 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400933 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400934 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400935 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500936 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
937 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +0000938 }
939 }
940 };
941
942 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
943 @Override
944 public void onReceive(Context context, Intent intent) {
945 String action = intent.getAction();
946
947 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400948 // Keep track of screen on/off state, but do not turn off the notification light
949 // until user passes through the lock screen or views the notification.
950 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +0100951 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400952 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
953 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +0100954 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500955 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -0500956 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
957 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500958 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700959 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
960 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
961 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400962 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500963 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -0700964 }
Rubin Xue95057a2016-04-01 16:49:25 +0100965 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000966 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +0100967 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400968 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -0500969 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000970 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400971 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
972 // turn off LED when user passes through lock screen
973 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400974 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400975 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -0400976 // reload per-user settings
977 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -0400978 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200979 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -0400980 mConditionProviders.onUserSwitched(user);
981 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400982 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -0400983 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000984 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400985 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
986 if (userId != USER_NULL) {
987 mUserProfiles.updateCache(context);
988 readDefaultApprovedServices(userId);
989 }
John Spurlock21258a32015-05-27 18:22:55 -0400990 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400991 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
John Spurlock21258a32015-05-27 18:22:55 -0400992 mZenModeHelper.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -0400993 mRankingHelper.onUserRemoved(user);
994 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500995 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -0400996 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500997 mConditionProviders.onUserUnlocked(user);
998 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400999 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001000 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 }
1002 }
1003 };
1004
John Spurlock7c74f782015-06-04 13:01:42 -04001005 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001006 private final Uri NOTIFICATION_BADGING_URI
1007 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001008 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1009 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001010 private final Uri NOTIFICATION_RATE_LIMIT_URI
1011 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001012
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001013 SettingsObserver(Handler handler) {
1014 super(handler);
1015 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001016
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001017 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001018 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001019 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1020 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001021 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001022 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001023 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1024 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001025 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001026 }
1027
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001028 @Override public void onChange(boolean selfChange, Uri uri) {
1029 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001030 }
1031
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001032 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001033 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001034 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001035 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1036 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001037 if (mNotificationPulseEnabled != pulseEnabled) {
1038 mNotificationPulseEnabled = pulseEnabled;
1039 updateNotificationPulse();
1040 }
1041 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001042 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1043 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1044 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1045 }
Chris Wren89aa2262017-05-05 18:05:56 -04001046 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1047 mRankingHelper.updateBadgingEnabled();
1048 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001049 }
1050 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001051
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001052 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001053 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001054
Daniel Sandleredbb3802012-11-13 20:49:47 -08001055 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1056 int[] ar = r.getIntArray(resid);
1057 if (ar == null) {
1058 return def;
1059 }
1060 final int len = ar.length > maxlen ? maxlen : ar.length;
1061 long[] out = new long[len];
1062 for (int i=0; i<len; i++) {
1063 out[i] = ar[i];
1064 }
1065 return out;
1066 }
1067
Jeff Brownb880d882014-02-10 19:47:07 -08001068 public NotificationManagerService(Context context) {
1069 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001070 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001071 }
1072
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001073 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001074 @VisibleForTesting
1075 void setAudioManager(AudioManager audioMananger) {
1076 mAudioManager = audioMananger;
1077 }
1078
1079 @VisibleForTesting
1080 void setVibrator(Vibrator vibrator) {
1081 mVibrator = vibrator;
1082 }
1083
1084 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001085 void setLights(Light light) {
1086 mNotificationLight = light;
1087 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001088 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001089 }
1090
1091 @VisibleForTesting
1092 void setScreenOn(boolean on) {
1093 mScreenOn = on;
1094 }
1095
1096 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001097 int getNotificationRecordCount() {
1098 synchronized (mNotificationLock) {
1099 int count = mNotificationList.size() + mNotificationsByKey.size()
1100 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1101 // subtract duplicates
1102 for (NotificationRecord posted : mNotificationList) {
1103 if (mNotificationsByKey.containsKey(posted.getKey())) {
1104 count--;
1105 }
1106 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001107 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001108 }
1109 }
1110
1111 return count;
1112 }
1113 }
1114
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001115 void clearNotifications() {
1116 mEnqueuedNotifications.clear();
1117 mNotificationList.clear();
1118 mNotificationsByKey.clear();
1119 mSummaryByGroupKey.clear();
1120 }
1121
Julia Reynolds080361e2017-07-13 11:23:12 -04001122 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001123 void addNotification(NotificationRecord r) {
1124 mNotificationList.add(r);
1125 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001126 if (r.sbn.isGroup()) {
1127 mSummaryByGroupKey.put(r.getGroupKey(), r);
1128 }
1129 }
1130
1131 @VisibleForTesting
1132 void addEnqueuedNotification(NotificationRecord r) {
1133 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001134 }
1135
1136 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001137 void setSystemReady(boolean systemReady) {
1138 mSystemReady = systemReady;
1139 }
1140
1141 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001142 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001143 mHandler = handler;
1144 }
1145
Chris Wrend4054312016-06-24 17:07:40 -04001146 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001147 void setFallbackVibrationPattern(long[] vibrationPattern) {
1148 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001149 }
1150
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001151 @VisibleForTesting
1152 void setPackageManager(IPackageManager packageManager) {
1153 mPackageManager = packageManager;
1154 }
1155
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001156 @VisibleForTesting
1157 void setRankingHelper(RankingHelper rankingHelper) {
1158 mRankingHelper = rankingHelper;
1159 }
1160
1161 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001162 void setRankingHandler(RankingHandler rankingHandler) {
1163 mRankingHandler = rankingHandler;
1164 }
1165
1166 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001167 void setIsTelevision(boolean isTelevision) {
1168 mIsTelevision = isTelevision;
1169 }
1170
Julia Reynolds76c096d2017-06-19 08:16:04 -04001171 @VisibleForTesting
1172 void setUsageStats(NotificationUsageStats us) {
1173 mUsageStats = us;
1174 }
1175
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001176 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001177 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001178 void init(Looper looper, IPackageManager packageManager,
1179 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001180 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001181 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001182 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001183 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds8aebf352017-06-26 11:35:33 -04001184 ActivityManager activityManager, GroupHelper groupHelper) {
Chris Wren54bbef42014-07-09 18:37:56 -04001185 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001186 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1187 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1188 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1189
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001190 mAm = ActivityManager.getService();
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001191 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001192 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001193 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1194 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001195 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Julia Reynolds2a128742016-11-28 14:29:25 -05001196 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001197 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001198 mActivityManager = activityManager;
San Mehat3ee13172010-02-04 20:54:43 -08001199
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001200 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001201 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001202 String[] extractorNames;
1203 try {
1204 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1205 } catch (Resources.NotFoundException e) {
1206 extractorNames = new String[0];
1207 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001208 mUsageStats = usageStats;
Chris Wren51017d02015-12-15 15:34:46 -05001209 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Chris Wren54bbef42014-07-09 18:37:56 -04001210 mRankingHelper = new RankingHelper(getContext(),
Julia Reynolds85769912016-10-25 09:08:57 -04001211 getContext().getPackageManager(),
Chris Wren51017d02015-12-15 15:34:46 -05001212 mRankingHandler,
Chris Wren5eab2b72015-06-16 13:56:22 -04001213 mUsageStats,
Chris Wren54bbef42014-07-09 18:37:56 -04001214 extractorNames);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001215 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001216 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001217 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001218 @Override
1219 public void onConfigChanged() {
1220 savePolicyFile();
1221 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001222
1223 @Override
1224 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001225 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001226 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001227 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1228 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001229 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001230 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001231 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001232 }
1233 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001234
1235 @Override
1236 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001237 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1238 }
John Spurlock056c5192014-04-20 21:52:01 -04001239 });
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001240 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001241 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001242
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001243 // This is a ManagedServices object that keeps track of the listeners.
1244 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001245
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001246 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001247 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001248
1249 mPolicyFile = policyFile;
1250 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001251
Adam Lesinski182f73f2013-12-05 16:48:06 -08001252 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001253 if (mStatusBar != null) {
1254 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001257 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1258 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001259
Daniel Sandleredbb3802012-11-13 20:49:47 -08001260 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001261 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001262 VIBRATE_PATTERN_MAXLEN,
1263 DEFAULT_VIBRATE_PATTERN);
1264
Beverly5d463b62017-07-26 14:13:40 -04001265 mInCallNotificationUri = Uri.parse("file://" +
1266 resources.getString(R.string.config_inCallNotificationSound));
1267 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1268 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1269 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
1270 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
1271 .build();
1272 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1273
Chris Wren5116a822014-06-04 15:59:50 -04001274 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1275
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001276 // Don't start allowing notifications until the setup wizard has run once.
1277 // After that, including subsequent boots, init with notifications turned on.
1278 // This works on the first boot because the setup wizard will toggle this
1279 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001280 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001281 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001282 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001283 }
John Spurlockb2278d62015-04-07 12:47:12 -04001284 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001285 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001286
John Spurlockb408e8e2014-04-23 21:12:45 -04001287 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001288 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001289
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001290 mSettingsObserver = new SettingsObserver(mHandler);
1291
1292 mArchive = new Archive(resources.getInteger(
1293 R.integer.config_notificationServiceArchiveSize));
1294
1295 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1296 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1297 }
1298
1299 @Override
1300 public void onStart() {
1301 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1302 @Override
1303 public void repost(int userId, NotificationRecord r) {
1304 try {
1305 if (DBG) {
1306 Slog.d(TAG, "Reposting " + r.getKey());
1307 }
1308 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1309 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1310 r.sbn.getNotification(), userId);
1311 } catch (Exception e) {
1312 Slog.e(TAG, "Cannot un-snooze notification", e);
1313 }
1314 }
1315 }, mUserProfiles);
1316
1317 final File systemDir = new File(Environment.getDataDirectory(), "system");
1318
1319 init(Looper.myLooper(),
1320 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1321 getLocalService(LightsManager.class),
1322 new NotificationListeners(AppGlobals.getPackageManager()),
1323 new NotificationAssistants(AppGlobals.getPackageManager()),
1324 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1325 null, snoozeHelper, new NotificationUsageStats(getContext()),
1326 new AtomicFile(new File(systemDir, "notification_policy.xml")),
1327 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
1328 getGroupHelper());
1329
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001330 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001331 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001332 filter.addAction(Intent.ACTION_SCREEN_ON);
1333 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001334 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001335 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001336 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001337 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001338 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001339 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001340 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001341 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001342 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001343
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001344 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001345 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001346 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001347 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001348 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1349 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1350 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001351 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1352 null);
1353
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001354 IntentFilter suspendedPkgFilter = new IntentFilter();
1355 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1356 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1357 suspendedPkgFilter, null, null);
1358
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001359 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001360 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1361 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001362
Julia Reynolds2a128742016-11-28 14:29:25 -05001363 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1364 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1365 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1366
Julia Reynoldsb852e562017-06-06 16:14:18 -04001367 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1368 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1369
Beverlyd4f96492017-08-02 13:36:11 -04001370 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1371 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1372
Adam Lesinski182f73f2013-12-05 16:48:06 -08001373 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1374 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 }
1376
Julia Reynolds8aebf352017-06-26 11:35:33 -04001377 private GroupHelper getGroupHelper() {
1378 return new GroupHelper(new GroupHelper.Callback() {
1379 @Override
1380 public void addAutoGroup(String key) {
1381 synchronized (mNotificationLock) {
1382 addAutogroupKeyLocked(key);
1383 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001384 }
1385
1386 @Override
1387 public void removeAutoGroup(String key) {
1388 synchronized (mNotificationLock) {
1389 removeAutogroupKeyLocked(key);
1390 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001391 }
1392
1393 @Override
1394 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1395 createAutoGroupSummary(userId, pkg, triggeringKey);
1396 }
1397
1398 @Override
1399 public void removeAutoGroupSummary(int userId, String pkg) {
1400 synchronized (mNotificationLock) {
1401 clearAutogroupSummaryLocked(userId, pkg);
1402 }
1403 }
1404 });
1405 }
1406
John Spurlocke7a835b2015-05-13 10:47:05 -04001407 private void sendRegisteredOnlyBroadcast(String action) {
1408 getContext().sendBroadcastAsUser(new Intent(action)
1409 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1410 }
1411
Adam Lesinski182f73f2013-12-05 16:48:06 -08001412 @Override
1413 public void onBootPhase(int phase) {
1414 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1415 // no beeping until we're basically done booting
1416 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001417
Adam Lesinski182f73f2013-12-05 16:48:06 -08001418 // Grab our optional AudioService
1419 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001420 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001421 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001422 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001423 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1424 // This observer will force an update when observe is called, causing us to
1425 // bind to listener services.
1426 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001427 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001428 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001429 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 }
1431 }
1432
Julia Reynolds88860ce2017-06-01 16:55:49 -04001433 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001434 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001435 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001436 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001437 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001438 mListenerHints = hints;
1439 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001440 }
1441
Julia Reynolds88860ce2017-06-01 16:55:49 -04001442 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001443 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001444 final long updatedSuppressedEffects = calculateSuppressedEffects();
1445 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1446 final List<ComponentName> suppressors = getSuppressors();
1447 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1448 mEffectsSuppressors = suppressors;
1449 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001450 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001451 }
1452
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001453 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1454 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001455 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1456 // cancel
1457 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1458 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1459 null);
1460 }
Julia Reynolds60315332017-04-04 14:29:07 -04001461 mRankingHelper.updateNotificationChannel(pkg, uid, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001462
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001463 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001464 final NotificationChannel modifiedChannel =
1465 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001466 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001467 pkg, UserHandle.getUserHandleForUid(uid),
1468 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001469 }
1470
Julia Reynolds924eed12017-01-19 09:52:07 -05001471 savePolicyFile();
1472 }
1473
Bryce Lee7219ada2016-04-08 10:54:23 -07001474 private ArrayList<ComponentName> getSuppressors() {
1475 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1476 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1477 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1478
1479 for (ManagedServiceInfo info : serviceInfoList) {
1480 names.add(info.component);
1481 }
1482 }
1483
1484 return names;
1485 }
1486
1487 private boolean removeDisabledHints(ManagedServiceInfo info) {
1488 return removeDisabledHints(info, 0);
1489 }
1490
1491 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1492 boolean removed = false;
1493
1494 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1495 final int hint = mListenersDisablingEffects.keyAt(i);
1496 final ArraySet<ManagedServiceInfo> listeners =
1497 mListenersDisablingEffects.valueAt(i);
1498
1499 if (hints == 0 || (hint & hints) == hint) {
1500 removed = removed || listeners.remove(info);
1501 }
1502 }
1503
1504 return removed;
1505 }
1506
1507 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1508 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1509 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1510 }
1511
1512 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1513 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1514 }
1515
1516 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1517 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1518 }
1519 }
1520
1521 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1522 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1523 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1524 }
1525
1526 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1527 hintListeners.add(info);
1528 }
1529
1530 private int calculateHints() {
1531 int hints = 0;
1532 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1533 int hint = mListenersDisablingEffects.keyAt(i);
1534 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1535
1536 if (!serviceInfoList.isEmpty()) {
1537 hints |= hint;
1538 }
1539 }
1540
1541 return hints;
1542 }
1543
1544 private long calculateSuppressedEffects() {
1545 int hints = calculateHints();
1546 long suppressedEffects = 0;
1547
1548 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1549 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1550 }
1551
1552 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1553 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1554 }
1555
1556 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1557 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1558 }
1559
1560 return suppressedEffects;
1561 }
1562
Julia Reynolds88860ce2017-06-01 16:55:49 -04001563 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001564 private void updateInterruptionFilterLocked() {
1565 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1566 if (interruptionFilter == mInterruptionFilter) return;
1567 mInterruptionFilter = interruptionFilter;
1568 scheduleInterruptionFilterChanged(interruptionFilter);
1569 }
1570
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001571 @VisibleForTesting
1572 INotificationManager getBinderService() {
1573 return INotificationManager.Stub.asInterface(mService);
1574 }
1575
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001576 @VisibleForTesting
1577 NotificationManagerInternal getInternalService() {
1578 return mInternalService;
1579 }
1580
Adam Lesinski182f73f2013-12-05 16:48:06 -08001581 private final IBinder mService = new INotificationManager.Stub() {
1582 // Toasts
1583 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001586 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001587 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001588 if (DBG) {
1589 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1590 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001592
1593 if (pkg == null || callback == null) {
1594 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1595 return ;
1596 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001597 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001598 final boolean isPackageSuspended =
1599 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001600
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001601 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001602 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1603 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001604 Slog.e(TAG, "Suppressing toast from package " + pkg
1605 + (isPackageSuspended
1606 ? " due to package suspended by administrator."
1607 : " by user request."));
1608 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001609 }
1610
1611 synchronized (mToastQueue) {
1612 int callingPid = Binder.getCallingPid();
1613 long callingId = Binder.clearCallingIdentity();
1614 try {
1615 ToastRecord record;
Beverly4ee785b2017-08-11 12:49:56 -04001616 int index;
1617 // All packages aside from the android package can enqueue one toast at a time
1618 if (!isSystemToast) {
1619 index = indexOfToastPackageLocked(pkg);
1620 } else {
1621 index = indexOfToastLocked(pkg, callback);
1622 }
1623
1624 // If the package already has a toast, we update its toast
1625 // in the queue, we don't move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001626 if (index >= 0) {
1627 record = mToastQueue.get(index);
1628 record.update(duration);
Beverly4ee785b2017-08-11 12:49:56 -04001629 record.update(callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001630 } else {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001631 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07001632 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001633 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001634 mToastQueue.add(record);
1635 index = mToastQueue.size() - 1;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001636 }
Beverly4ee785b2017-08-11 12:49:56 -04001637 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001638 // If it's at index 0, it's the current toast. It doesn't matter if it's
1639 // new or just been updated. Call back and tell it to show itself.
1640 // If the callback fails, this will remove it from the list, so don't
1641 // assume that it's valid after this.
1642 if (index == 0) {
1643 showNextToastLocked();
1644 }
1645 } finally {
1646 Binder.restoreCallingIdentity(callingId);
1647 }
1648 }
1649 }
1650
1651 @Override
1652 public void cancelToast(String pkg, ITransientNotification callback) {
1653 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1654
1655 if (pkg == null || callback == null) {
1656 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1657 return ;
1658 }
1659
1660 synchronized (mToastQueue) {
1661 long callingId = Binder.clearCallingIdentity();
1662 try {
1663 int index = indexOfToastLocked(pkg, callback);
1664 if (index >= 0) {
1665 cancelToastLocked(index);
1666 } else {
1667 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1668 + " callback=" + callback);
1669 }
1670 } finally {
1671 Binder.restoreCallingIdentity(callingId);
1672 }
1673 }
1674 }
1675
1676 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001677 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001678 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001679 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001680 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001681 }
1682
1683 @Override
1684 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001685 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001686 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1687 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04001688 // Don't allow client applications to cancel foreground service notis or autobundled
1689 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001690 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1691 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04001692 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001693 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001694 }
1695
1696 @Override
1697 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001698 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001699
1700 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1701 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1702
1703 // Calling from user space, don't allow the canceling of actively
1704 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04001705 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001706 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001707 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001708 }
1709
1710 @Override
1711 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
John Spurlock7340fc82014-04-24 18:50:12 -04001712 checkCallerIsSystem();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001713
Chris Wrenacf424a2016-03-15 12:48:55 -04001714 mRankingHelper.setEnabled(pkg, uid, enabled);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001715 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04001716 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001717 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1718 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1719 }
Chris Wrenacf424a2016-03-15 12:48:55 -04001720 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001721 }
1722
1723 /**
1724 * Use this when you just want to know if notifications are OK for this package.
1725 */
1726 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001727 public boolean areNotificationsEnabled(String pkg) {
1728 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1729 }
1730
1731 /**
1732 * Use this when you just want to know if notifications are OK for this package.
1733 */
1734 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001735 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001736 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001737
1738 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001739 }
1740
Chris Wren54bbef42014-07-09 18:37:56 -04001741 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001742 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001743 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05001744 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001745 }
1746
1747 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05001748 public boolean canShowBadge(String pkg, int uid) {
1749 checkCallerIsSystem();
1750 return mRankingHelper.canShowBadge(pkg, uid);
1751 }
1752
1753 @Override
1754 public void setShowBadge(String pkg, int uid, boolean showBadge) {
1755 checkCallerIsSystem();
1756 mRankingHelper.setShowBadge(pkg, uid, showBadge);
1757 savePolicyFile();
1758 }
1759
1760 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05001761 public void createNotificationChannelGroups(String pkg,
1762 ParceledListSlice channelGroupList) throws RemoteException {
1763 checkCallerIsSystemOrSameApp(pkg);
1764 List<NotificationChannelGroup> groups = channelGroupList.getList();
1765 final int groupSize = groups.size();
1766 for (int i = 0; i < groupSize; i++) {
1767 final NotificationChannelGroup group = groups.get(i);
1768 Preconditions.checkNotNull(group, "group in list is null");
1769 mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
1770 true /* fromTargetApp */);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001771 mListeners.notifyNotificationChannelGroupChanged(pkg,
1772 UserHandle.of(UserHandle.getCallingUserId()), group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001773 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Julia Reynolds59e152e2017-01-25 17:42:53 -05001774 }
1775 savePolicyFile();
1776 }
1777
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001778 private void createNotificationChannelsImpl(String pkg, int uid,
1779 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001780 List<NotificationChannel> channels = channelsList.getList();
1781 final int channelsSize = channels.size();
1782 for (int i = 0; i < channelsSize; i++) {
1783 final NotificationChannel channel = channels.get(i);
1784 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001785 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001786 true /* fromTargetApp */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001787 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001788 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001789 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
1790 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001791 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001792 savePolicyFile();
1793 }
1794
1795 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04001796 public void createNotificationChannels(String pkg,
1797 ParceledListSlice channelsList) throws RemoteException {
1798 checkCallerIsSystemOrSameApp(pkg);
1799 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
1800 }
1801
1802 @Override
1803 public void createNotificationChannelsForPackage(String pkg, int uid,
1804 ParceledListSlice channelsList) throws RemoteException {
1805 checkCallerIsSystem();
1806 createNotificationChannelsImpl(pkg, uid, channelsList);
1807 }
1808
1809 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001810 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001811 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001812 return mRankingHelper.getNotificationChannel(
1813 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001814 }
1815
1816 @Override
1817 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001818 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001819 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04001820 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001821 }
1822
1823 @Override
1824 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001825 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001826 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001827 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
1828 throw new IllegalArgumentException("Cannot delete default channel");
1829 }
1830 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001831 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
1832 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
1833 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001834 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001835 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
1836 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001837 savePolicyFile();
1838 }
1839
1840 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04001841 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
1842 String pkg) {
1843 checkCallerIsSystemOrSameApp(pkg);
1844 return new ParceledListSlice<>(new ArrayList(
1845 mRankingHelper.getNotificationChannelGroups(pkg, Binder.getCallingUid())));
1846 }
1847
1848 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001849 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04001850 checkCallerIsSystemOrSameApp(pkg);
1851
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001852 final int callingUid = Binder.getCallingUid();
1853 NotificationChannelGroup groupToDelete =
1854 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
1855 if (groupToDelete != null) {
1856 List<NotificationChannel> deletedChannels =
1857 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
1858 for (int i = 0; i < deletedChannels.size(); i++) {
1859 final NotificationChannel deletedChannel = deletedChannels.get(i);
1860 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
1861 true,
1862 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
1863 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001864 mListeners.notifyNotificationChannelChanged(pkg,
1865 UserHandle.getUserHandleForUid(callingUid),
1866 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001867 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
1868 }
1869 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001870 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
1871 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001872 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04001873 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04001874 }
1875
1876 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001877 public void updateNotificationChannelForPackage(String pkg, int uid,
1878 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05001879 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05001880 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001881 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001882 }
1883
1884 @Override
1885 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001886 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05001887 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001888 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001889 }
1890
1891 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05001892 public int getNumNotificationChannelsForPackage(String pkg, int uid,
1893 boolean includeDeleted) {
1894 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
1895 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
1896 .getList().size();
1897 }
1898
1899 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04001900 public boolean onlyHasDefaultChannel(String pkg, int uid) {
1901 enforceSystemOrSystemUI("onlyHasDefaultChannel");
1902 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
1903 }
1904
1905 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04001906 public int getDeletedChannelCount(String pkg, int uid) {
1907 enforceSystemOrSystemUI("getDeletedChannelCount");
1908 return mRankingHelper.getDeletedChannelCount(pkg, uid);
1909 }
1910
1911 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05001912 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
1913 String pkg, int uid, boolean includeDeleted) {
1914 checkCallerIsSystem();
1915 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted);
1916 }
1917
1918 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05001919 public NotificationChannelGroup getNotificationChannelGroupForPackage(
1920 String groupId, String pkg, int uid) {
1921 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
1922 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
1923 }
1924
1925 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001926 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
1927 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001928 return mRankingHelper.getNotificationChannels(
1929 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001930 }
1931
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001932 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05001933 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001934 checkCallerIsSystem();
1935
1936 // Cancel posted notifications
1937 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
1938 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
1939
Julia Reynoldsb852e562017-06-06 16:14:18 -04001940 final String[] packages = new String[] {packageName};
1941 final int[] uids = new int[] {uid};
1942
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001943 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04001944 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001945 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001946
1947 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04001948 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001949
1950 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05001951 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04001952 mRankingHelper.onPackagesChanged(
1953 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05001954 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001955
1956 savePolicyFile();
1957 }
1958
1959
Adam Lesinski182f73f2013-12-05 16:48:06 -08001960 /**
1961 * System-only API for getting a list of current (i.e. not cleared) notifications.
1962 *
1963 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04001964 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001965 */
1966 @Override
1967 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
1968 // enforce() will ensure the calling uid has the correct permission
1969 getContext().enforceCallingOrSelfPermission(
1970 android.Manifest.permission.ACCESS_NOTIFICATIONS,
1971 "NotificationManagerService.getActiveNotifications");
1972
1973 StatusBarNotification[] tmp = null;
1974 int uid = Binder.getCallingUid();
1975
1976 // noteOp will check to make sure the callingPkg matches the uid
1977 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
1978 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001979 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001980 tmp = new StatusBarNotification[mNotificationList.size()];
1981 final int N = mNotificationList.size();
1982 for (int i=0; i<N; i++) {
1983 tmp[i] = mNotificationList.get(i).sbn;
1984 }
1985 }
1986 }
1987 return tmp;
1988 }
1989
1990 /**
Dan Sandler994349c2015-04-15 11:02:54 -04001991 * Public API for getting a list of current notifications for the calling package/uid.
1992 *
Julia Reynolds573c6532017-01-24 17:44:38 -05001993 * Note that since notification posting is done asynchronously, this will not return
1994 * notifications that are in the process of being posted.
1995 *
Dan Sandler994349c2015-04-15 11:02:54 -04001996 * @returns A list of all the package's notifications, in natural order.
1997 */
1998 @Override
1999 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2000 int incomingUserId) {
2001 checkCallerIsSystemOrSameApp(pkg);
2002 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2003 Binder.getCallingUid(), incomingUserId, true, false,
2004 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002005 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002006 final ArrayMap<String, StatusBarNotification> map
2007 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002008 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002009 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002010 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2011 mNotificationList.get(i).sbn);
2012 if (sbn != null) {
2013 map.put(sbn.getKey(), sbn);
2014 }
2015 }
2016 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2017 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2018 if (sbn != null) {
2019 map.put(sbn.getKey(), sbn);
2020 }
2021 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002022 final int M = mEnqueuedNotifications.size();
2023 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002024 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2025 mEnqueuedNotifications.get(i).sbn);
2026 if (sbn != null) {
2027 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002028 }
2029 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002030 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2031 list.addAll(map.values());
2032 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002033 }
Dan Sandler994349c2015-04-15 11:02:54 -04002034 }
2035
Chris Wren6676dab2016-12-21 18:26:27 -05002036 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2037 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002038 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002039 // We could pass back a cloneLight() but clients might get confused and
2040 // try to send this thing back to notify() again, which would not work
2041 // very well.
2042 return new StatusBarNotification(
2043 sbn.getPackageName(),
2044 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002045 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2046 sbn.getNotification().clone(),
2047 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2048 }
2049 return null;
2050 }
2051
Dan Sandler994349c2015-04-15 11:02:54 -04002052 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002053 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2054 *
2055 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2056 */
2057 @Override
2058 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2059 // enforce() will ensure the calling uid has the correct permission
2060 getContext().enforceCallingOrSelfPermission(
2061 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2062 "NotificationManagerService.getHistoricalNotifications");
2063
2064 StatusBarNotification[] tmp = null;
2065 int uid = Binder.getCallingUid();
2066
2067 // noteOp will check to make sure the callingPkg matches the uid
2068 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2069 == AppOpsManager.MODE_ALLOWED) {
2070 synchronized (mArchive) {
2071 tmp = mArchive.getArray(count);
2072 }
2073 }
2074 return tmp;
2075 }
2076
2077 /**
2078 * Register a listener binder directly with the notification manager.
2079 *
2080 * Only works with system callers. Apps should extend
2081 * {@link android.service.notification.NotificationListenerService}.
2082 */
2083 @Override
2084 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002085 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002086 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002087 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002088 }
2089
2090 /**
2091 * Remove a listener binder directly
2092 */
2093 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002094 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002095 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002096 }
2097
2098 /**
2099 * Allow an INotificationListener to simulate a "clear all" operation.
2100 *
2101 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2102 *
2103 * @param token The binder for the listener, to check that the caller is allowed
2104 */
2105 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002106 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002107 final int callingUid = Binder.getCallingUid();
2108 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002109 long identity = Binder.clearCallingIdentity();
2110 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002111 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002112 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
John Spurlocka4294292014-03-24 18:02:32 -04002113 if (keys != null) {
2114 final int N = keys.length;
2115 for (int i = 0; i < N; i++) {
2116 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002117 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002118 final int userId = r.sbn.getUserId();
2119 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002120 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002121 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002122 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002123 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002124 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2125 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2126 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002127 }
2128 } else {
2129 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002130 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002131 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002132 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002133 } finally {
2134 Binder.restoreCallingIdentity(identity);
2135 }
2136 }
2137
Chris Wrenab41eec2016-01-04 18:01:27 -05002138 /**
2139 * Handle request from an approved listener to re-enable itself.
2140 *
2141 * @param component The componenet to be re-enabled, caller must match package.
2142 */
2143 @Override
2144 public void requestBindListener(ComponentName component) {
2145 checkCallerIsSystemOrSameApp(component.getPackageName());
2146 long identity = Binder.clearCallingIdentity();
2147 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002148 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002149 mAssistants.isComponentEnabledForCurrentProfiles(component)
2150 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002151 : mListeners;
2152 manager.setComponentState(component, true);
2153 } finally {
2154 Binder.restoreCallingIdentity(identity);
2155 }
2156 }
2157
2158 @Override
2159 public void requestUnbindListener(INotificationListener token) {
2160 long identity = Binder.clearCallingIdentity();
2161 try {
2162 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002163 synchronized (mNotificationLock) {
2164 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2165 info.getOwner().setComponentState(info.component, false);
2166 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002167 } finally {
2168 Binder.restoreCallingIdentity(identity);
2169 }
2170 }
2171
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002172 @Override
2173 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002174 long identity = Binder.clearCallingIdentity();
2175 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002176 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002177 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2178 if (keys != null) {
2179 final int N = keys.length;
2180 for (int i = 0; i < N; i++) {
2181 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2182 if (r == null) continue;
2183 final int userId = r.sbn.getUserId();
2184 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2185 !mUserProfiles.isCurrentProfile(userId)) {
2186 throw new SecurityException("Disallowed call from listener: "
2187 + info.service);
2188 }
2189 if (!r.isSeen()) {
2190 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
2191 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002192 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002193 : userId,
Adam Lesinskic8e87292015-06-10 15:33:45 -07002194 UsageEvents.Event.USER_INTERACTION);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002195 r.setSeen();
2196 }
2197 }
2198 }
2199 }
2200 } finally {
2201 Binder.restoreCallingIdentity(identity);
2202 }
2203 }
2204
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002205 /**
2206 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2207 *
2208 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2209 *
Julia Reynolds79672302017-01-12 08:30:16 -05002210 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002211 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002212 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002213 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002214 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002215 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2216 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2217 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002218 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002219 }
2220
Adam Lesinski182f73f2013-12-05 16:48:06 -08002221 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002222 * Allow an INotificationListener to snooze a single notification until a context.
2223 *
2224 * @param token The binder for the listener, to check that the caller is allowed
2225 */
2226 @Override
2227 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2228 String key, String snoozeCriterionId) {
2229 long identity = Binder.clearCallingIdentity();
2230 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002231 synchronized (mNotificationLock) {
2232 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2233 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2234 }
Julia Reynolds79672302017-01-12 08:30:16 -05002235 } finally {
2236 Binder.restoreCallingIdentity(identity);
2237 }
2238 }
2239
2240 /**
2241 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002242 *
2243 * @param token The binder for the listener, to check that the caller is allowed
2244 */
2245 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002246 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002247 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002248 long identity = Binder.clearCallingIdentity();
2249 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002250 synchronized (mNotificationLock) {
2251 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2252 snoozeNotificationInt(key, duration, null, info);
2253 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002254 } finally {
2255 Binder.restoreCallingIdentity(identity);
2256 }
2257 }
2258
2259 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002260 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002261 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002262 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002263 */
2264 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002265 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002266 long identity = Binder.clearCallingIdentity();
2267 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002268 synchronized (mNotificationLock) {
2269 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002270 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002271 unsnoozeNotificationInt(key, info);
2272 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002273 } finally {
2274 Binder.restoreCallingIdentity(identity);
2275 }
2276 }
2277
2278 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002279 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2280 *
2281 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2282 *
2283 * @param token The binder for the listener, to check that the caller is allowed
2284 */
2285 @Override
2286 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2287 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002288 final int callingUid = Binder.getCallingUid();
2289 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002290 long identity = Binder.clearCallingIdentity();
2291 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002292 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002293 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002294 if (info.supportsProfiles()) {
2295 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2296 + "from " + info.component
2297 + " use cancelNotification(key) instead.");
2298 } else {
2299 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2300 pkg, tag, id, info.userid);
2301 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002302 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002303 } finally {
2304 Binder.restoreCallingIdentity(identity);
2305 }
2306 }
2307
2308 /**
2309 * Allow an INotificationListener to request the list of outstanding notifications seen by
2310 * the current user. Useful when starting up, after which point the listener callbacks
2311 * should be used.
2312 *
2313 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002314 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002315 * @returns The return value will contain the notifications specified in keys, in that
2316 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002317 */
2318 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002319 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002320 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002321 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002322 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002323 final boolean getKeys = keys != null;
2324 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002325 final ArrayList<StatusBarNotification> list
2326 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002327 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002328 final NotificationRecord r = getKeys
2329 ? mNotificationsByKey.get(keys[i])
2330 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002331 if (r == null) continue;
2332 StatusBarNotification sbn = r.sbn;
2333 if (!isVisibleToListener(sbn, info)) continue;
2334 StatusBarNotification sbnToSend =
2335 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2336 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002337 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002338 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002339 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002340 }
2341
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002342 /**
2343 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2344 * seen by the current user. Useful when starting up, after which point the listener
2345 * callbacks should be used.
2346 *
2347 * @param token The binder for the listener, to check that the caller is allowed
2348 * @returns The return value will contain the notifications specified in keys, in that
2349 * order, or if keys is null, all the notifications, in natural order.
2350 */
2351 @Override
2352 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2353 INotificationListener token, int trim) {
2354 synchronized (mNotificationLock) {
2355 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2356 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2357 final int N = snoozedRecords.size();
2358 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2359 for (int i=0; i < N; i++) {
2360 final NotificationRecord r = snoozedRecords.get(i);
2361 if (r == null) continue;
2362 StatusBarNotification sbn = r.sbn;
2363 if (!isVisibleToListener(sbn, info)) continue;
2364 StatusBarNotification sbnToSend =
2365 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2366 list.add(sbnToSend);
2367 }
2368 return new ParceledListSlice<>(list);
2369 }
2370 }
2371
Adam Lesinski182f73f2013-12-05 16:48:06 -08002372 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002373 public void requestHintsFromListener(INotificationListener token, int hints) {
2374 final long identity = Binder.clearCallingIdentity();
2375 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002376 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002377 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002378 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2379 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2380 | HINT_HOST_DISABLE_CALL_EFFECTS;
2381 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002382 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002383 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002384 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002385 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002386 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002387 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002388 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002389 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002390 } finally {
2391 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002392 }
2393 }
2394
2395 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002396 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002397 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002398 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002399 }
2400 }
2401
2402 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002403 public void requestInterruptionFilterFromListener(INotificationListener token,
2404 int interruptionFilter) throws RemoteException {
2405 final long identity = Binder.clearCallingIdentity();
2406 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002407 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002408 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2409 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002410 updateInterruptionFilterLocked();
2411 }
2412 } finally {
2413 Binder.restoreCallingIdentity(identity);
2414 }
2415 }
2416
2417 @Override
2418 public int getInterruptionFilterFromListener(INotificationListener token)
2419 throws RemoteException {
2420 synchronized (mNotificationLight) {
2421 return mInterruptionFilter;
2422 }
2423 }
2424
2425 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002426 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2427 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002428 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002429 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2430 if (info == null) return;
2431 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2432 }
2433 }
2434
2435 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002436 public int getZenMode() {
2437 return mZenModeHelper.getZenMode();
2438 }
2439
2440 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002441 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002442 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002443 return mZenModeHelper.getConfig();
2444 }
2445
2446 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002447 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002448 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002449 final long identity = Binder.clearCallingIdentity();
2450 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002451 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002452 } finally {
2453 Binder.restoreCallingIdentity(identity);
2454 }
2455 }
2456
2457 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002458 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002459 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002460 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002461 }
2462
2463 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002464 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2465 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002466 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002467 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002468 }
2469
2470 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002471 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002472 throws RemoteException {
2473 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2474 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2475 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2476 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002477 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002478
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002479 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2480 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002481 }
2482
2483 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002484 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002485 throws RemoteException {
2486 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2487 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2488 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2489 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2490 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002491
Julia Reynolds361e82d32016-02-26 18:19:49 -05002492 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002493 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002494 }
2495
2496 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002497 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2498 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002499 // Verify that they can modify zen rules.
2500 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2501
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002502 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002503 }
2504
2505 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05002506 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2507 Preconditions.checkNotNull(packageName, "Package name is null");
2508 enforceSystemOrSystemUI("removeAutomaticZenRules");
2509
2510 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2511 }
2512
2513 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05002514 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2515 Preconditions.checkNotNull(owner, "Owner is null");
2516 enforceSystemOrSystemUI("getRuleInstanceCount");
2517
2518 return mZenModeHelper.getCurrentInstanceCount(owner);
2519 }
2520
2521 @Override
John Spurlock80774932015-05-07 17:38:50 -04002522 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2523 enforcePolicyAccess(pkg, "setInterruptionFilter");
2524 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2525 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2526 final long identity = Binder.clearCallingIdentity();
2527 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002528 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04002529 } finally {
2530 Binder.restoreCallingIdentity(identity);
2531 }
2532 }
2533
2534 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04002535 public void notifyConditions(final String pkg, IConditionProvider provider,
2536 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04002537 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2538 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04002539 mHandler.post(new Runnable() {
2540 @Override
2541 public void run() {
2542 mConditionProviders.notifyConditions(pkg, info, conditions);
2543 }
2544 });
John Spurlocke77bb362014-04-26 10:24:59 -04002545 }
2546
Julia Reynolds38e6ca42016-08-08 08:38:09 -04002547 @Override
2548 public void requestUnbindProvider(IConditionProvider provider) {
2549 long identity = Binder.clearCallingIdentity();
2550 try {
2551 // allow bound services to disable themselves
2552 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2553 info.getOwner().setComponentState(info.component, false);
2554 } finally {
2555 Binder.restoreCallingIdentity(identity);
2556 }
2557 }
2558
2559 @Override
2560 public void requestBindProvider(ComponentName component) {
2561 checkCallerIsSystemOrSameApp(component.getPackageName());
2562 long identity = Binder.clearCallingIdentity();
2563 try {
2564 mConditionProviders.setComponentState(component, true);
2565 } finally {
2566 Binder.restoreCallingIdentity(identity);
2567 }
2568 }
2569
John Spurlocke77bb362014-04-26 10:24:59 -04002570 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002571 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04002572 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2573 message);
John Spurlock7340fc82014-04-24 18:50:12 -04002574 }
2575
Julia Reynolds48034f82016-03-09 10:15:16 -05002576 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2577 try {
2578 checkCallerIsSystemOrSameApp(pkg);
2579 } catch (SecurityException e) {
2580 getContext().enforceCallingPermission(
2581 android.Manifest.permission.STATUS_BAR_SERVICE,
2582 message);
2583 }
2584 }
2585
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002586 private void enforcePolicyAccess(int uid, String method) {
2587 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2588 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2589 return;
2590 }
2591 boolean accessAllowed = false;
2592 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2593 final int packageCount = packages.length;
2594 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002595 if (mConditionProviders.isPackageOrComponentAllowed(
2596 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002597 accessAllowed = true;
2598 }
2599 }
2600 if (!accessAllowed) {
2601 Slog.w(TAG, "Notification policy access denied calling " + method);
2602 throw new SecurityException("Notification policy access denied");
2603 }
2604 }
2605
John Spurlock80774932015-05-07 17:38:50 -04002606 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04002607 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2608 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2609 return;
2610 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04002611 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002612 if (!checkPolicyAccess(pkg)) {
2613 Slog.w(TAG, "Notification policy access denied calling " + method);
2614 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04002615 }
2616 }
2617
John Spurlock80774932015-05-07 17:38:50 -04002618 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002619 return mConditionProviders.isPackageOrComponentAllowed(
2620 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04002621 }
2622
2623 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04002624 try {
2625 int uid = getContext().getPackageManager().getPackageUidAsUser(
2626 pkg, UserHandle.getCallingUserId());
2627 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2628 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2629 -1, true)) {
2630 return true;
2631 }
2632 } catch (NameNotFoundException e) {
2633 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002634 }
John Spurlock80774932015-05-07 17:38:50 -04002635 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002636 }
2637
John Spurlock7340fc82014-04-24 18:50:12 -04002638 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002639 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002640 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04002641 final DumpFilter filter = DumpFilter.parseFromArguments(args);
2642 if (filter != null && filter.stats) {
2643 dumpJson(pw, filter);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05002644 } else if (filter != null && filter.proto) {
2645 dumpProto(fd, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04002646 } else {
2647 dumpImpl(pw, filter);
2648 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002649 }
John Spurlockb4782522014-08-22 14:54:46 -04002650
2651 @Override
2652 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07002653 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04002654 }
John Spurlock2b122f42014-08-27 16:29:47 -04002655
2656 @Override
2657 public boolean matchesCallFilter(Bundle extras) {
2658 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02002659 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002660 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02002661 extras,
2662 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2663 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2664 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04002665 }
John Spurlock530052a2014-11-30 16:26:19 -05002666
2667 @Override
2668 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002669 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04002670 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05002671 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002672
Christopher Tatef9767d62015-04-08 14:35:43 -07002673 // Backup/restore interface
2674 @Override
2675 public byte[] getBackupPayload(int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002676 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002677 //TODO: http://b/22388012
2678 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002679 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2680 return null;
2681 }
songjinshi9bf22712017-02-04 10:47:45 +08002682 synchronized(mPolicyFile) {
2683 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2684 try {
2685 writePolicyXml(baos, true /*forBackup*/);
2686 return baos.toByteArray();
2687 } catch (IOException e) {
2688 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2689 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002690 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002691 return null;
2692 }
2693
2694 @Override
2695 public void applyRestore(byte[] payload, int user) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002696 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2697 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2698 if (payload == null) {
2699 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2700 return;
2701 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002702 //TODO: http://b/22388012
2703 if (user != UserHandle.USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002704 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2705 return;
2706 }
songjinshi9bf22712017-02-04 10:47:45 +08002707 synchronized(mPolicyFile) {
2708 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2709 try {
2710 readPolicyXml(bais, true /*forRestore*/);
2711 savePolicyFile();
2712 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2713 Slog.w(TAG, "applyRestore: error reading payload", e);
2714 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002715 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002716 }
2717
John Spurlock1fc476d2015-04-14 16:05:20 -04002718 @Override
John Spurlock80774932015-05-07 17:38:50 -04002719 public boolean isNotificationPolicyAccessGranted(String pkg) {
2720 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002721 }
2722
2723 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05002724 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2725 enforceSystemOrSystemUIOrSamePackage(pkg,
2726 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002727 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002728 }
2729
2730 @Override
John Spurlock80774932015-05-07 17:38:50 -04002731 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2732 throws RemoteException {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002733 checkCallerIsSystemOrShell();
Julia Reynolds68263d12017-06-21 14:21:19 -04002734 if (!mActivityManager.isLowRamDevice()) {
2735 mConditionProviders.setPackageOrComponentEnabled(
2736 pkg, getCallingUserHandle().getIdentifier(), true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002737
Julia Reynolds68263d12017-06-21 14:21:19 -04002738 getContext().sendBroadcastAsUser(new Intent(
2739 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2740 .setPackage(pkg)
2741 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2742 getCallingUserHandle(), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002743
Julia Reynolds68263d12017-06-21 14:21:19 -04002744 savePolicyFile();
2745 }
John Spurlock80774932015-05-07 17:38:50 -04002746 }
2747
2748 @Override
2749 public Policy getNotificationPolicy(String pkg) {
2750 enforcePolicyAccess(pkg, "getNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002751 final long identity = Binder.clearCallingIdentity();
2752 try {
2753 return mZenModeHelper.getNotificationPolicy();
2754 } finally {
2755 Binder.restoreCallingIdentity(identity);
2756 }
2757 }
2758
2759 @Override
John Spurlock80774932015-05-07 17:38:50 -04002760 public void setNotificationPolicy(String pkg, Policy policy) {
2761 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04002762 final long identity = Binder.clearCallingIdentity();
2763 try {
2764 mZenModeHelper.setNotificationPolicy(policy);
2765 } finally {
2766 Binder.restoreCallingIdentity(identity);
2767 }
2768 }
Chris Wren51017d02015-12-15 15:34:46 -05002769
2770 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04002771 public List<String> getEnabledNotificationListenerPackages() {
2772 checkCallerIsSystem();
2773 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
2774 }
2775
2776 @Override
2777 public List<ComponentName> getEnabledNotificationListeners(int userId) {
2778 checkCallerIsSystem();
2779 return mListeners.getAllowedComponents(userId);
2780 }
2781
2782 @Override
2783 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
2784 Preconditions.checkNotNull(listener);
2785 checkCallerIsSystemOrSameApp(listener.getPackageName());
2786 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2787 getCallingUserHandle().getIdentifier());
2788 }
2789
2790 @Override
2791 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
2792 int userId) {
2793 Preconditions.checkNotNull(listener);
2794 checkCallerIsSystem();
2795 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
2796 userId);
2797 }
2798
2799 @Override
2800 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
2801 Preconditions.checkNotNull(assistant);
2802 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002803 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04002804 getCallingUserHandle().getIdentifier());
2805 }
2806
2807 @Override
2808 public void setNotificationListenerAccessGranted(ComponentName listener,
2809 boolean granted) throws RemoteException {
2810 setNotificationListenerAccessGrantedForUser(
2811 listener, getCallingUserHandle().getIdentifier(), granted);
2812 }
2813
2814 @Override
2815 public void setNotificationAssistantAccessGranted(ComponentName assistant,
2816 boolean granted) throws RemoteException {
2817 setNotificationAssistantAccessGrantedForUser(
2818 assistant, getCallingUserHandle().getIdentifier(), granted);
2819 }
2820
2821 @Override
2822 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
2823 boolean granted) throws RemoteException {
2824 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04002825 checkCallerIsSystemOrShell();
Julia Reynolds68263d12017-06-21 14:21:19 -04002826 if (!mActivityManager.isLowRamDevice()) {
2827 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
2828 userId, false, granted);
2829 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
2830 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002831
Julia Reynolds68263d12017-06-21 14:21:19 -04002832 getContext().sendBroadcastAsUser(new Intent(
2833 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2834 .setPackage(listener.getPackageName())
2835 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2836 getCallingUserHandle(), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002837
Julia Reynolds68263d12017-06-21 14:21:19 -04002838 savePolicyFile();
2839 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04002840 }
2841
2842 @Override
2843 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
2844 int userId, boolean granted) throws RemoteException {
2845 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04002846 checkCallerIsSystemOrShell();
Julia Reynolds68263d12017-06-21 14:21:19 -04002847 if (!mActivityManager.isLowRamDevice()) {
2848 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
2849 userId, false, granted);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002850 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
Julia Reynolds68263d12017-06-21 14:21:19 -04002851 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002852
Julia Reynolds68263d12017-06-21 14:21:19 -04002853 getContext().sendBroadcastAsUser(new Intent(
2854 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2855 .setPackage(assistant.getPackageName())
2856 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
2857 getCallingUserHandle(), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002858
Julia Reynolds68263d12017-06-21 14:21:19 -04002859 savePolicyFile();
2860 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04002861 }
2862
2863 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002864 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
2865 Adjustment adjustment) throws RemoteException {
2866 final long identity = Binder.clearCallingIdentity();
2867 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002868 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002869 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002870 int N = mEnqueuedNotifications.size();
2871 for (int i = 0; i < N; i++) {
2872 final NotificationRecord n = mEnqueuedNotifications.get(i);
2873 if (Objects.equals(adjustment.getKey(), n.getKey())
2874 && Objects.equals(adjustment.getUser(), n.getUserId())) {
2875 applyAdjustment(n, adjustment);
2876 break;
2877 }
2878 }
2879 }
2880 } finally {
2881 Binder.restoreCallingIdentity(identity);
2882 }
2883 }
2884
2885 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05002886 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04002887 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05002888 final long identity = Binder.clearCallingIdentity();
2889 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002890 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002891 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002892 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2893 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05002894 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002895 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04002896 } finally {
2897 Binder.restoreCallingIdentity(identity);
2898 }
2899 }
2900
2901 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05002902 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04002903 List<Adjustment> adjustments) throws RemoteException {
2904
2905 final long identity = Binder.clearCallingIdentity();
2906 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002907 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002908 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002909 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05002910 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
2911 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002912 }
2913 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002914 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05002915 } finally {
2916 Binder.restoreCallingIdentity(identity);
2917 }
2918 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002919
2920 @Override
2921 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002922 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002923 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002924 Preconditions.checkNotNull(pkg);
2925 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002926
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002927 verifyPrivilegedListener(token, user);
2928 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002929 }
2930
2931 @Override
2932 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002933 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2934 Preconditions.checkNotNull(pkg);
2935 Preconditions.checkNotNull(user);
2936 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002937
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002938 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
2939 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002940 }
2941
2942 @Override
2943 public ParceledListSlice<NotificationChannelGroup>
2944 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002945 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
2946 Preconditions.checkNotNull(pkg);
2947 Preconditions.checkNotNull(user);
2948 verifyPrivilegedListener(token, user);
2949
2950 List<NotificationChannelGroup> groups = new ArrayList<>();
2951 groups.addAll(mRankingHelper.getNotificationChannelGroups(
2952 pkg, getUidForPackageAndUser(pkg, user)));
2953 return new ParceledListSlice<>(groups);
2954 }
2955
2956 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002957 ManagedServiceInfo info;
2958 synchronized (mNotificationLock) {
2959 info = mListeners.checkServiceTokenLocked(token);
2960 }
Julia Reynoldsda781472017-04-12 09:41:16 -04002961 if (!hasCompanionDevice(info)) {
2962 throw new SecurityException(info + " does not have access");
2963 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002964 if (!info.enabledAndUserMatches(user.getIdentifier())) {
2965 throw new SecurityException(info + " does not have access");
2966 }
2967 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002968
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002969 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
2970 int uid = 0;
2971 long identity = Binder.clearCallingIdentity();
2972 try {
2973 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
2974 } finally {
2975 Binder.restoreCallingIdentity(identity);
2976 }
2977 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002978 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04002979
2980 @Override
2981 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2982 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
2983 throws RemoteException {
2984 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
2985 }
John Spurlock1fc476d2015-04-14 16:05:20 -04002986 };
John Spurlocka4294292014-03-24 18:02:32 -04002987
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002988 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
2989 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002990 return;
2991 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04002992 if (adjustment.getSignals() != null) {
2993 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002994 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002995 }
2996 }
2997
Julia Reynolds88860ce2017-06-01 16:55:49 -04002998 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04002999 void addAutogroupKeyLocked(String key) {
3000 NotificationRecord r = mNotificationsByKey.get(key);
3001 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003002 return;
3003 }
Julia Reynolds51710712017-07-19 13:48:07 -04003004 if (r.sbn.getOverrideGroupKey() == null) {
3005 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3006 EventLogTags.writeNotificationAutogrouped(key);
3007 mRankingHandler.requestSort();
3008 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003009 }
3010
Julia Reynolds88860ce2017-06-01 16:55:49 -04003011 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003012 void removeAutogroupKeyLocked(String key) {
3013 NotificationRecord r = mNotificationsByKey.get(key);
3014 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003015 return;
3016 }
Julia Reynolds51710712017-07-19 13:48:07 -04003017 if (r.sbn.getOverrideGroupKey() != null) {
3018 addAutoGroupAdjustment(r, null);
3019 EventLogTags.writeNotificationUnautogrouped(key);
3020 mRankingHandler.requestSort();
3021 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003022 }
3023
3024 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3025 Bundle signals = new Bundle();
3026 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3027 Adjustment adjustment =
3028 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3029 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003030 }
3031
3032 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003033 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003034 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3035 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3036 if (summaries != null && summaries.containsKey(pkg)) {
3037 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003038 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003039 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003040 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003041 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003042 }
3043 }
3044 }
3045
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003046 @GuardedBy("mNotificationLock")
3047 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3048 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3049 return summaries != null && summaries.containsKey(sbn.getPackageName());
3050 }
3051
Julia Reynoldse46bb372016-03-17 11:05:58 -04003052 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003053 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3054 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003055 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003056 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3057 if (notificationRecord == null) {
3058 // The notification could have been cancelled again already. A successive
3059 // adjustment will post a summary if needed.
3060 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003061 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003062 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3063 userId = adjustedSbn.getUser().getIdentifier();
3064 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3065 if (summaries == null) {
3066 summaries = new ArrayMap<>();
3067 }
3068 mAutobundledSummaries.put(userId, summaries);
3069 if (!summaries.containsKey(pkg)) {
3070 // Add summary
3071 final ApplicationInfo appInfo =
3072 adjustedSbn.getNotification().extras.getParcelable(
3073 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3074 final Bundle extras = new Bundle();
3075 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003076 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003077 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003078 new Notification.Builder(getContext(), channelId)
3079 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003080 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003081 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003082 .setGroup(GroupHelper.AUTOGROUP_KEY)
3083 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3084 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3085 .setColor(adjustedSbn.getNotification().color)
3086 .setLocalOnly(true)
3087 .build();
3088 summaryNotification.extras.putAll(extras);
3089 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3090 if (appIntent != null) {
3091 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3092 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3093 }
3094 final StatusBarNotification summarySbn =
3095 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003096 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003097 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003098 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3099 adjustedSbn.getInitialPid(), summaryNotification,
3100 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3101 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003102 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003103 notificationRecord.getChannel());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003104 summaries.put(pkg, summarySbn.getKey());
3105 }
3106 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003107 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003108 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003109 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003110 }
3111 }
3112
John Spurlock32fe4c62014-10-02 12:16:02 -04003113 private String disableNotificationEffects(NotificationRecord record) {
3114 if (mDisableNotificationEffects) {
3115 return "booleanState";
3116 }
3117 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3118 return "listenerHints";
3119 }
3120 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3121 return "callState";
3122 }
3123 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003124 };
3125
3126 private void dumpJson(PrintWriter pw, DumpFilter filter) {
3127 JSONObject dump = new JSONObject();
3128 try {
3129 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003130 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3131 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003132 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003133 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003134 } catch (JSONException e) {
3135 e.printStackTrace();
3136 }
3137 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003138 }
3139
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003140 private void dumpProto(FileDescriptor fd, DumpFilter filter) {
3141 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3142 synchronized (mNotificationLock) {
3143 long records = proto.start(NotificationServiceDumpProto.RECORDS);
3144 int N = mNotificationList.size();
3145 if (N > 0) {
3146 for (int i = 0; i < N; i++) {
3147 final NotificationRecord nr = mNotificationList.get(i);
3148 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3149 nr.dump(proto, filter.redact);
3150 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.POSTED);
3151 }
3152 }
3153 N = mEnqueuedNotifications.size();
3154 if (N > 0) {
3155 for (int i = 0; i < N; i++) {
3156 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3157 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3158 nr.dump(proto, filter.redact);
3159 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.ENQUEUED);
3160 }
3161 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003162 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3163 N = snoozed.size();
3164 if (N > 0) {
3165 for (int i = 0; i < N; i++) {
3166 final NotificationRecord nr = snoozed.get(i);
3167 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3168 nr.dump(proto, filter.redact);
3169 proto.write(NotificationRecordProto.STATE, NotificationServiceProto.SNOOZED);
3170 }
3171 }
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003172 proto.end(records);
3173 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003174
3175 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3176 mZenModeHelper.dump(proto);
3177 for (ComponentName suppressor : mEffectsSuppressors) {
3178 proto.write(ZenModeProto.SUPPRESSORS, suppressor.toString());
3179 }
3180 proto.end(zenLog);
3181
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003182 proto.flush();
3183 }
3184
John Spurlock25e2d242014-06-27 13:58:23 -04003185 void dumpImpl(PrintWriter pw, DumpFilter filter) {
3186 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003187 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003188 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003189 }
3190 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003191 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003192 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003193
John Spurlock50806fc2014-07-15 10:22:02 -04003194 if (!zenOnly) {
3195 synchronized (mToastQueue) {
3196 N = mToastQueue.size();
3197 if (N > 0) {
3198 pw.println(" Toast Queue:");
3199 for (int i=0; i<N; i++) {
3200 mToastQueue.get(i).dump(pw, " ", filter);
3201 }
3202 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003203 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003204 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003205 }
3206
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003207 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003208 if (!zenOnly) {
3209 N = mNotificationList.size();
John Spurlock25e2d242014-06-27 13:58:23 -04003210 if (N > 0) {
John Spurlock50806fc2014-07-15 10:22:02 -04003211 pw.println(" Notification List:");
John Spurlock25e2d242014-06-27 13:58:23 -04003212 for (int i=0; i<N; i++) {
John Spurlock50806fc2014-07-15 10:22:02 -04003213 final NotificationRecord nr = mNotificationList.get(i);
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003214 if (filter.filtered && !filter.matches(nr.sbn)) continue;
Dan Sandlera1770312015-07-10 13:59:29 -04003215 nr.dump(pw, " ", getContext(), filter.redact);
John Spurlock25e2d242014-06-27 13:58:23 -04003216 }
3217 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003218 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003219
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003220 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003221 N = mLights.size();
3222 if (N > 0) {
3223 pw.println(" Lights List:");
3224 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003225 if (i == N - 1) {
3226 pw.print(" > ");
3227 } else {
3228 pw.print(" ");
3229 }
3230 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003231 }
3232 pw.println(" ");
3233 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003234 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3235 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003236 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3237 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003238 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003239 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003240 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003241 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003242 }
3243 pw.println(" mArchive=" + mArchive.toString());
3244 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003245 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003246 while (iter.hasNext()) {
3247 final StatusBarNotification sbn = iter.next();
3248 if (filter != null && !filter.matches(sbn)) continue;
3249 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003250 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003251 if (iter.hasNext()) pw.println(" ...");
3252 break;
3253 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003254 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003255
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003256 if (!zenOnly) {
3257 N = mEnqueuedNotifications.size();
3258 if (N > 0) {
3259 pw.println(" Enqueued Notification List:");
3260 for (int i = 0; i < N; i++) {
3261 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3262 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3263 nr.dump(pw, " ", getContext(), filter.redact);
3264 }
3265 pw.println(" ");
3266 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003267
3268 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003269 }
3270 }
3271
John Spurlock50806fc2014-07-15 10:22:02 -04003272 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003273 pw.println("\n Ranking Config:");
3274 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003275
John Spurlock50806fc2014-07-15 10:22:02 -04003276 pw.println("\n Notification listeners:");
3277 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003278 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3279 pw.print(" mListenersDisablingEffects: (");
3280 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003281 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003282 final int hint = mListenersDisablingEffects.keyAt(i);
3283 if (i > 0) pw.print(';');
3284 pw.print("hint[" + hint + "]:");
3285
3286 final ArraySet<ManagedServiceInfo> listeners =
3287 mListenersDisablingEffects.valueAt(i);
3288 final int listenerSize = listeners.size();
3289
3290 for (int j = 0; j < listenerSize; j++) {
3291 if (i > 0) pw.print(',');
3292 final ManagedServiceInfo listener = listeners.valueAt(i);
3293 pw.print(listener.component);
3294 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003295 }
3296 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003297 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003298 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003299 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003300
Julia Reynolds520df6e2017-02-13 09:05:10 -05003301 if (!filter.filtered || zenOnly) {
3302 pw.println("\n Zen Mode:");
3303 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3304 mZenModeHelper.dump(pw, " ");
3305
3306 pw.println("\n Zen Log:");
3307 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003308 }
3309
John Spurlocke77bb362014-04-26 10:24:59 -04003310 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003311 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003312
3313 pw.println("\n Group summaries:");
3314 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3315 NotificationRecord r = entry.getValue();
3316 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3317 if (mNotificationsByKey.get(r.getKey()) != r) {
3318 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003319 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003320 }
3321 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003322
3323 if (!zenOnly) {
3324 pw.println("\n Usage Stats:");
3325 mUsageStats.dump(pw, " ", filter);
3326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 }
3328 }
3329
Adam Lesinski182f73f2013-12-05 16:48:06 -08003330 /**
3331 * The private API only accessible to the system process.
3332 */
3333 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3334 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003335 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003336 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003337 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003338 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003339 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003340
3341 @Override
3342 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3343 int userId) {
3344 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003345 mHandler.post(new Runnable() {
3346 @Override
3347 public void run() {
3348 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003349 removeForegroundServiceFlagByListLocked(
3350 mEnqueuedNotifications, pkg, notificationId, userId);
3351 removeForegroundServiceFlagByListLocked(
3352 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003353 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003354 }
3355 });
3356 }
3357
Julia Reynolds88860ce2017-06-01 16:55:49 -04003358 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003359 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003360 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3361 int userId) {
3362 NotificationRecord r = findNotificationByListLocked(
3363 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003364 if (r == null) {
3365 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003366 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003367 StatusBarNotification sbn = r.sbn;
3368 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3369 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3370 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3371 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3372 sbn.getNotification().flags =
3373 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3374 mRankingHelper.sort(mNotificationList);
3375 mListeners.notifyPostedLocked(sbn, sbn /* oldSbn */);
Christoph Studer365e4c32014-09-18 20:35:36 +02003376 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003377 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003379 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04003380 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003381 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04003382 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003383 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3384 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04003385 }
John Spurlock7340fc82014-04-24 18:50:12 -04003386 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003387
Scott Greenwald9b05c612013-06-25 23:44:05 -04003388 final int userId = ActivityManager.handleIncomingUser(callingPid,
3389 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07003390 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07003391
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003392 if (pkg == null || notification == null) {
3393 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3394 + " id=" + id + " notification=" + notification);
3395 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003396
3397 // The system can post notifications for any package, let us resolve that.
3398 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3399
Julia Reynoldse46bb372016-03-17 11:05:58 -04003400 // Fix the notification as best we can.
3401 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003402 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06003403 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
3404 (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04003405 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04003406
3407 int canColorize = mPackageManagerClient.checkPermission(
3408 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3409 if (canColorize == PERMISSION_GRANTED) {
3410 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3411 } else {
3412 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3413 }
3414
Julia Reynoldse46bb372016-03-17 11:05:58 -04003415 } catch (NameNotFoundException e) {
3416 Slog.e(TAG, "Cannot create a context for sending app", e);
3417 return;
3418 }
3419
Chris Wren888b7a82016-06-17 15:47:19 -04003420 mUsageStats.registerEnqueuedByApp(pkg);
3421
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003422 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04003423 String channelId = notification.getChannelId();
3424 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3425 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05003426 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003427 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003428 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003429 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003430 final String noChannelStr = "No Channel found for "
3431 + "pkg=" + pkg
3432 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04003433 + ", id=" + id
3434 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003435 + ", opPkg=" + opPkg
3436 + ", callingUid=" + callingUid
3437 + ", userId=" + userId
3438 + ", incomingUserId=" + incomingUserId
3439 + ", notificationUid=" + notificationUid
3440 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003441 Log.e(TAG, noChannelStr);
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003442 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
Geoffrey Pitschcadb5dc2017-04-11 11:35:02 -04003443 "Failed to post notification on channel \"" + channelId + "\"\n" +
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003444 "See log for more details");
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003445 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003446 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003447
Chris Wrena61f1792016-08-04 11:24:42 -04003448 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003449 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003450 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003451 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Chris Wrena61f1792016-08-04 11:24:42 -04003452
Julia Reynolds5e702192017-08-18 09:22:40 -04003453 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3454 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003455 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07003456 }
3457
Felipe Lemedd85da62016-06-28 11:29:54 -07003458 // Whitelist pending intents.
3459 if (notification.allPendingIntents != null) {
3460 final int intentCount = notification.allPendingIntents.size();
3461 if (intentCount > 0) {
3462 final ActivityManagerInternal am = LocalServices
3463 .getService(ActivityManagerInternal.class);
3464 final long duration = LocalServices.getService(
3465 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3466 for (int i = 0; i < intentCount; i++) {
3467 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3468 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07003469 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3470 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07003471 }
3472 }
3473 }
3474 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07003475
Chris Wren47633422016-01-22 09:56:59 -05003476 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 }
3478
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003479 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003480 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003481 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003482 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3483 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003484 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04003485 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04003486 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003487 }
3488 }
3489
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003490 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3491 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003492 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003493 try {
3494 return getContext().getPackageManager()
3495 .getPackageUidAsUser(opPackageName, userId);
3496 } catch (NameNotFoundException e) {
3497 /* ignore */
3498 }
3499 }
3500 return callingUid;
3501 }
3502
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003503 /**
3504 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3505 *
3506 * Has side effects.
3507 */
3508 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04003509 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003510 final String pkg = r.sbn.getPackageName();
Sailesh Nepale8bde702017-07-21 11:44:04 -07003511 final String dialerPackage =
3512 getContext().getSystemService(TelecomManager.class).getSystemDialerPackage();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003513 final boolean isSystemNotification =
Sailesh Nepale8bde702017-07-21 11:44:04 -07003514 isUidSystemOrPhone(callingUid) || ("android".equals(pkg))
3515 || TextUtils.equals(pkg, dialerPackage);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003516 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3517
3518 // Limit the number of notifications that any given package except the android
3519 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
3520 if (!isSystemNotification && !isNotificationFromListener) {
3521 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003522 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3523 // Ephemeral apps have some special constraints for notifications.
3524 // They are not allowed to create new notifications however they are allowed to
3525 // update notifications created by the system (e.g. a foreground service
3526 // notification).
3527 throw new SecurityException("Instant app " + pkg
3528 + " cannot create notifications");
3529 }
3530
3531 // rate limit updates that aren't completed progress notifications
3532 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04003533 && !r.getNotification().hasCompletedProgress()
3534 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003535
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003536 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3537 if (appEnqueueRate > mMaxPackageEnqueueRate) {
3538 mUsageStats.registerOverRateQuota(pkg);
3539 final long now = SystemClock.elapsedRealtime();
3540 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3541 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04003542 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003543 mLastOverRateLogTime = now;
3544 }
3545 return false;
3546 }
3547 }
3548
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003549 // limit the number of outstanding notificationrecords an app can have
3550 int count = getNotificationCountLocked(pkg, userId, id, tag);
3551 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3552 mUsageStats.registerOverCountQuota(pkg);
3553 Slog.e(TAG, "Package has already posted or enqueued " + count
3554 + " notifications. Not showing more. package=" + pkg);
3555 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003556 }
3557 }
3558 }
3559
3560 // snoozed apps
3561 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05003562 MetricsLogger.action(r.getLogMaker()
3563 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3564 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003565 if (DBG) {
3566 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3567 }
3568 mSnoozeHelper.update(userId, r);
3569 savePolicyFile();
3570 return false;
3571 }
3572
3573
3574 // blocked apps
3575 if (isBlocked(r, mUsageStats)) {
3576 return false;
3577 }
3578
3579 return true;
3580 }
3581
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003582 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3583 String excludedTag) {
3584 int count = 0;
3585 final int N = mNotificationList.size();
3586 for (int i = 0; i < N; i++) {
3587 final NotificationRecord existing = mNotificationList.get(i);
3588 if (existing.sbn.getPackageName().equals(pkg)
3589 && existing.sbn.getUserId() == userId) {
3590 if (existing.sbn.getId() == excludedId
3591 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3592 continue;
3593 }
3594 count++;
3595 }
3596 }
3597 final int M = mEnqueuedNotifications.size();
3598 for (int i = 0; i < M; i++) {
3599 final NotificationRecord existing = mEnqueuedNotifications.get(i);
3600 if (existing.sbn.getPackageName().equals(pkg)
3601 && existing.sbn.getUserId() == userId) {
3602 count++;
3603 }
3604 }
3605 return count;
3606 }
3607
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003608 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3609 final String pkg = r.sbn.getPackageName();
3610 final int callingUid = r.sbn.getUid();
3611
3612 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3613 if (isPackageSuspended) {
3614 Slog.e(TAG, "Suppressing notification from package due to package "
3615 + "suspended by administrator.");
3616 usageStats.registerSuspendedByAdmin(r);
3617 return isPackageSuspended;
3618 }
3619
Julia Reynolds4da79702017-06-01 11:06:10 -04003620 final boolean isBlocked =
3621 mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04003622 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003623 if (isBlocked) {
3624 Slog.e(TAG, "Suppressing notification from package by user request.");
3625 usageStats.registerBlocked(r);
3626 }
3627 return isBlocked;
3628 }
3629
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003630 protected class SnoozeNotificationRunnable implements Runnable {
3631 private final String mKey;
3632 private final long mDuration;
3633 private final String mSnoozeCriterionId;
3634
3635 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3636 mKey = key;
3637 mDuration = duration;
3638 mSnoozeCriterionId = snoozeCriterionId;
3639 }
3640
3641 @Override
3642 public void run() {
3643 synchronized (mNotificationLock) {
3644 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3645 if (r != null) {
3646 snoozeLocked(r);
3647 }
3648 }
3649 }
3650
Julia Reynolds88860ce2017-06-01 16:55:49 -04003651 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003652 void snoozeLocked(NotificationRecord r) {
3653 if (r.sbn.isGroup()) {
3654 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
3655 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
3656 if (r.getNotification().isGroupSummary()) {
3657 // snooze summary and all children
3658 for (int i = 0; i < groupNotifications.size(); i++) {
3659 snoozeNotificationLocked(groupNotifications.get(i));
3660 }
3661 } else {
3662 // if there is a valid summary for this group, and we are snoozing the only
3663 // child, also snooze the summary
3664 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
3665 if (groupNotifications.size() != 2) {
3666 snoozeNotificationLocked(r);
3667 } else {
3668 // snooze summary and the one child
3669 for (int i = 0; i < groupNotifications.size(); i++) {
3670 snoozeNotificationLocked(groupNotifications.get(i));
3671 }
3672 }
3673 } else {
3674 snoozeNotificationLocked(r);
3675 }
3676 }
3677 } else {
3678 // just snooze the one notification
3679 snoozeNotificationLocked(r);
3680 }
3681 }
3682
Julia Reynolds88860ce2017-06-01 16:55:49 -04003683 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003684 void snoozeNotificationLocked(NotificationRecord r) {
3685 MetricsLogger.action(r.getLogMaker()
3686 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
3687 .setType(MetricsEvent.TYPE_CLOSE)
3688 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
3689 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04003690 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003691 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003692 updateLightsLocked();
3693 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003694 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003695 mSnoozeHelper.snooze(r);
3696 } else {
3697 mSnoozeHelper.snooze(r, mDuration);
3698 }
3699 savePolicyFile();
3700 }
3701 }
3702
Julia Reynoldsbaff4002016-12-15 11:34:26 -05003703 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05003704 private final NotificationRecord r;
3705 private final int userId;
3706
3707 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
3708 this.userId = userId;
3709 this.r = r;
3710 };
3711
3712 @Override
3713 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003714 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05003715 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05003716 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05003717
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003718 final StatusBarNotification n = r.sbn;
3719 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
3720 NotificationRecord old = mNotificationsByKey.get(n.getKey());
3721 if (old != null) {
3722 // Retain ranking information from previous record
3723 r.copyRankingInformation(old);
3724 }
3725
3726 final int callingUid = n.getUid();
3727 final int callingPid = n.getInitialPid();
3728 final Notification notification = n.getNotification();
3729 final String pkg = n.getPackageName();
3730 final int id = n.getId();
3731 final String tag = n.getTag();
3732
3733 // Handle grouped notifications and bail out early if we
3734 // can to avoid extracting signals.
3735 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
3736
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003737 // if this is a group child, unsnooze parent summary
3738 if (n.isGroup() && notification.isGroupChild()) {
3739 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
3740 }
3741
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003742 // This conditional is a dirty hack to limit the logging done on
3743 // behalf of the download manager without affecting other apps.
3744 if (!pkg.equals("com.android.providers.downloads")
3745 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
3746 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05003747 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003748 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05003749 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003750 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
3751 pkg, id, tag, userId, notification.toString(),
3752 enqueueStatus);
3753 }
Chris Wren6676dab2016-12-21 18:26:27 -05003754
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003755 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05003756
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003757 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003758 if (mAssistants.isEnabled()) {
3759 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003760 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003761 DELAY_FOR_ASSISTANT_TIME);
3762 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003763 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003764 }
3765 }
3766 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003767 }
3768
3769 protected class PostNotificationRunnable implements Runnable {
3770 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003771
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003772 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003773 this.key = key;
3774 }
3775
3776 @Override
3777 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003778 synchronized (mNotificationLock) {
3779 try {
3780 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003781 int N = mEnqueuedNotifications.size();
3782 for (int i = 0; i < N; i++) {
3783 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3784 if (Objects.equals(key, enqueued.getKey())) {
3785 r = enqueued;
3786 break;
Chris Wren6676dab2016-12-21 18:26:27 -05003787 }
Chris Wren6676dab2016-12-21 18:26:27 -05003788 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003789 if (r == null) {
3790 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
3791 return;
3792 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003793 NotificationRecord old = mNotificationsByKey.get(key);
3794 final StatusBarNotification n = r.sbn;
3795 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05003796 int index = indexOfNotificationLocked(n.getKey());
3797 if (index < 0) {
3798 mNotificationList.add(r);
3799 mUsageStats.registerPostedByApp(r);
3800 } else {
3801 old = mNotificationList.get(index);
3802 mNotificationList.set(index, r);
3803 mUsageStats.registerUpdatedByApp(r, old);
3804 // Make sure we don't lose the foreground service state.
3805 notification.flags |=
3806 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
3807 r.isUpdate = true;
3808 }
3809
3810 mNotificationsByKey.put(n.getKey(), r);
3811
3812 // Ensure if this is a foreground service that the proper additional
3813 // flags are set.
3814 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
3815 notification.flags |= Notification.FLAG_ONGOING_EVENT
3816 | Notification.FLAG_NO_CLEAR;
3817 }
3818
3819 applyZenModeLocked(r);
3820 mRankingHelper.sort(mNotificationList);
3821
3822 if (notification.getSmallIcon() != null) {
3823 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
3824 mListeners.notifyPostedLocked(n, oldSbn);
Julia Reynolds8aebf352017-06-26 11:35:33 -04003825 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
3826 mHandler.post(new Runnable() {
3827 @Override
3828 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003829 mGroupHelper.onNotificationPosted(
3830 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04003831 }
3832 });
3833 }
Chris Wren6676dab2016-12-21 18:26:27 -05003834 } else {
3835 Slog.e(TAG, "Not posting notification without small icon: " + notification);
3836 if (old != null && !old.isCanceled) {
3837 mListeners.notifyRemovedLocked(n,
Julia Reynoldsf619bc52017-03-17 08:32:23 -04003838 NotificationListenerService.REASON_ERROR);
Chris Wren6676dab2016-12-21 18:26:27 -05003839 mHandler.post(new Runnable() {
3840 @Override
3841 public void run() {
3842 mGroupHelper.onNotificationRemoved(n);
3843 }
3844 });
3845 }
3846 // ATTENTION: in a future release we will bail out here
3847 // so that we do not play sounds, show lights, etc. for invalid
3848 // notifications
3849 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
3850 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05003851 }
Chris Wren47633422016-01-22 09:56:59 -05003852
Chris Wren6676dab2016-12-21 18:26:27 -05003853 buzzBeepBlinkLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003854 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003855 int N = mEnqueuedNotifications.size();
3856 for (int i = 0; i < N; i++) {
3857 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
3858 if (Objects.equals(key, enqueued.getKey())) {
3859 mEnqueuedNotifications.remove(i);
3860 break;
3861 }
3862 }
Chris Wren6676dab2016-12-21 18:26:27 -05003863 }
Chris Wren47633422016-01-22 09:56:59 -05003864 }
3865 }
3866 }
3867
Christoph Studer265c1052014-07-23 17:14:33 +02003868 /**
3869 * Ensures that grouped notification receive their special treatment.
3870 *
3871 * <p>Cancels group children if the new notification causes a group to lose
3872 * its summary.</p>
3873 *
3874 * <p>Updates mSummaryByGroupKey.</p>
3875 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04003876 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02003877 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
3878 int callingUid, int callingPid) {
3879 StatusBarNotification sbn = r.sbn;
3880 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07003881 if (n.isGroupSummary() && !sbn.isAppGroup()) {
3882 // notifications without a group shouldn't be a summary, otherwise autobundling can
3883 // lead to bugs
3884 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
3885 }
3886
Christoph Studer265c1052014-07-23 17:14:33 +02003887 String group = sbn.getGroupKey();
3888 boolean isSummary = n.isGroupSummary();
3889
3890 Notification oldN = old != null ? old.sbn.getNotification() : null;
3891 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
3892 boolean oldIsSummary = old != null && oldN.isGroupSummary();
3893
3894 if (oldIsSummary) {
3895 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
3896 if (removedSummary != old) {
3897 String removedKey =
3898 removedSummary != null ? removedSummary.getKey() : "<null>";
3899 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
3900 ", removed=" + removedKey);
3901 }
3902 }
3903 if (isSummary) {
3904 mSummaryByGroupKey.put(group, r);
3905 }
3906
3907 // Clear out group children of the old notification if the update
3908 // causes the group summary to go away. This happens when the old
3909 // notification was a summary and the new one isn't, or when the old
3910 // notification was a summary and its group key changed.
3911 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04003912 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
3913 null);
Christoph Studer265c1052014-07-23 17:14:33 +02003914 }
3915 }
3916
Chris Wren93bb8b82016-03-29 14:35:05 -04003917 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04003918 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05003919 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04003920 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05003921 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
3922 REQUEST_CODE_TIMEOUT,
3923 new Intent(ACTION_NOTIFICATION_TIMEOUT)
3924 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
3925 .appendPath(record.getKey()).build())
3926 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
3927 .putExtra(EXTRA_KEY, record.getKey()),
3928 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05003929 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04003930 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05003931 }
3932 }
3933
3934 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04003935 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04003936 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04003937 boolean buzz = false;
3938 boolean beep = false;
3939 boolean blink = false;
3940
Chris Wrena3446562014-06-03 18:11:47 -04003941 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04003942 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04003943
3944 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04003945 final boolean aboveThreshold =
3946 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04003947
3948 // Remember if this notification already owns the notification channels.
3949 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
3950 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04003951 // These are set inside the conditional if the notification is allowed to make noise.
3952 boolean hasValidVibrate = false;
3953 boolean hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04003954
Julia Reynolds76c096d2017-06-19 08:16:04 -04003955 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04003956 // If the notification will appear in the status bar, it should send an accessibility
3957 // event
3958 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
Chris Wren93bb8b82016-03-29 14:35:05 -04003959 sendAccessibilityEvent(notification, record.sbn.getPackageName());
Julia Reynolds7c96b582017-05-25 12:35:36 -04003960 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04003961 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04003962 Uri soundUri = record.getSound();
3963 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
Julia Reynolds76c096d2017-06-19 08:16:04 -04003964
Julia Reynolds7c96b582017-05-25 12:35:36 -04003965 long[] vibration = record.getVibration();
3966 // Demote sound to vibration if vibration missing & phone in vibration mode.
3967 if (vibration == null
3968 && hasValidSound
3969 && (mAudioManager.getRingerModeInternal()
3970 == AudioManager.RINGER_MODE_VIBRATE)) {
3971 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04003972 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04003973 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01003974
Julia Reynolds76c096d2017-06-19 08:16:04 -04003975 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
3976
3977 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
3978 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04003979 if (hasValidSound) {
3980 mSoundNotificationKey = key;
3981 if (mInCall) {
3982 playInCallNotification();
3983 beep = true;
3984 } else {
3985 beep = playSound(record, soundUri);
3986 }
3987 }
Chris Wren93bb8b82016-03-29 14:35:05 -04003988
Julia Reynolds7c96b582017-05-25 12:35:36 -04003989 final boolean ringerModeSilent =
3990 mAudioManager.getRingerModeInternal()
3991 == AudioManager.RINGER_MODE_SILENT;
3992 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
3993 mVibrateNotificationKey = key;
3994
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07003995 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04003996 }
Chris Wrena3446562014-06-03 18:11:47 -04003997 }
3998 }
Chris Wren93bb8b82016-03-29 14:35:05 -04003999 }
4000 // If a notification is updated to remove the actively playing sound or vibrate,
4001 // cancel that feedback now
4002 if (wasBeep && !hasValidSound) {
4003 clearSoundLocked();
4004 }
4005 if (wasBuzz && !hasValidVibrate) {
4006 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004007 }
4008
4009 // light
4010 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004011 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004012 if (record.getLight() != null && aboveThreshold
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004013 && ((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05004014 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004015 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004016 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004017 if (mUseAttentionLight) {
4018 mAttentionLight.pulse();
4019 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004020 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004021 } else if (wasShowLights) {
4022 updateLightsLocked();
4023 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004024 if (buzz || beep || blink) {
Julia Reynolds445cfa82017-05-08 15:41:45 -04004025 MetricsLogger.action(record.getLogMaker()
4026 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4027 .setType(MetricsEvent.TYPE_OPEN)
4028 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4029 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004030 }
Chris Wrena3446562014-06-03 18:11:47 -04004031 }
4032
Julia Reynolds88860ce2017-06-01 16:55:49 -04004033 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004034 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004035 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004036 final Notification notification = record.getNotification();
4037 if(record.isUpdate
4038 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4039 return true;
4040 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004041
Julia Reynolds76c096d2017-06-19 08:16:04 -04004042 // muted by listener
4043 final String disableEffects = disableNotificationEffects(record);
4044 if (disableEffects != null) {
4045 ZenLog.traceDisableEffects(record, disableEffects);
4046 return true;
4047 }
4048
4049 // suppressed due to DND
4050 if (record.isIntercepted()) {
4051 return true;
4052 }
4053
4054 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004055 if (record.sbn.isGroup()) {
Julia Reynolds30203152017-05-26 13:36:31 -04004056 return notification.suppressAlertingDueToGrouping();
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004057 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004058
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004059 // Suppressed for being too recently noisy
4060 final String pkg = record.sbn.getPackageName();
4061 if (mUsageStats.isAlertRateLimited(pkg)) {
4062 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4063 return true;
4064 }
4065
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004066 return false;
4067 }
4068
Julia Reynolds0c299d42016-11-15 14:37:04 -05004069 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4070 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4071 // do not play notifications if there is a user of exclusive audio focus
Julia Reynolds2143e5d2017-01-17 16:28:48 -05004072 // or the device is in vibrate mode
4073 if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
4074 != AudioManager.RINGER_MODE_VIBRATE) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004075 final long identity = Binder.clearCallingIdentity();
4076 try {
4077 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4078 if (player != null) {
4079 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4080 + " with attributes " + record.getAudioAttributes());
4081 player.playAsync(soundUri, record.sbn.getUser(), looping,
4082 record.getAudioAttributes());
4083 return true;
4084 }
4085 } catch (RemoteException e) {
4086 } finally {
4087 Binder.restoreCallingIdentity(identity);
4088 }
4089 }
4090 return false;
4091 }
4092
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004093 private boolean playVibration(final NotificationRecord record, long[] vibration,
4094 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004095 // Escalate privileges so we can use the vibrator even if the
4096 // notifying app does not have the VIBRATE permission.
4097 long identity = Binder.clearCallingIdentity();
4098 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004099 final VibrationEffect effect;
4100 try {
4101 final boolean insistent =
4102 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4103 effect = VibrationEffect.createWaveform(
4104 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4105 } catch (IllegalArgumentException e) {
4106 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4107 Arrays.toString(vibration));
4108 return false;
4109 }
4110 if (delayVibForSound) {
4111 new Thread(() -> {
4112 // delay the vibration by the same amount as the notification sound
4113 final int waitMs = mAudioManager.getFocusRampTimeMs(
4114 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4115 record.getAudioAttributes());
4116 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4117 try {
4118 Thread.sleep(waitMs);
4119 } catch (InterruptedException e) { }
4120 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4121 effect, record.getAudioAttributes());
4122 }).start();
4123 } else {
4124 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4125 effect, record.getAudioAttributes());
4126 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004127 return true;
4128 } finally{
4129 Binder.restoreCallingIdentity(identity);
4130 }
4131 }
4132
Julia Reynolds7c96b582017-05-25 12:35:36 -04004133 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4134 final int currentUser;
4135 final long token = Binder.clearCallingIdentity();
4136 try {
4137 currentUser = ActivityManager.getCurrentUser();
4138 } finally {
4139 Binder.restoreCallingIdentity(token);
4140 }
4141 return (record.getUserId() == UserHandle.USER_ALL ||
4142 record.getUserId() == currentUser ||
4143 mUserProfiles.isCurrentProfile(record.getUserId()));
4144 }
4145
Beverly5d463b62017-07-26 14:13:40 -04004146 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01004147 new Thread() {
4148 @Override
4149 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04004150 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01004151 try {
Beverly5d463b62017-07-26 14:13:40 -04004152 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4153 if (player != null) {
4154 player.play(new Binder(), mInCallNotificationUri,
4155 mInCallNotificationAudioAttributes,
4156 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01004157 }
Beverly5d463b62017-07-26 14:13:40 -04004158 } catch (RemoteException e) {
4159 } finally {
4160 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01004161 }
4162 }
4163 }.start();
4164 }
4165
Julia Reynolds88860ce2017-06-01 16:55:49 -04004166 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004167 void showNextToastLocked() {
4168 ToastRecord record = mToastQueue.get(0);
4169 while (record != null) {
4170 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4171 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004172 record.callback.show(record.token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004173 scheduleTimeoutLocked(record);
4174 return;
4175 } catch (RemoteException e) {
4176 Slog.w(TAG, "Object died trying to show notification " + record.callback
4177 + " in package " + record.pkg);
4178 // remove it from the list and let the process die
4179 int index = mToastQueue.indexOf(record);
4180 if (index >= 0) {
4181 mToastQueue.remove(index);
4182 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004183 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004184 if (mToastQueue.size() > 0) {
4185 record = mToastQueue.get(0);
4186 } else {
4187 record = null;
4188 }
4189 }
4190 }
4191 }
4192
Julia Reynolds88860ce2017-06-01 16:55:49 -04004193 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004194 void cancelToastLocked(int index) {
4195 ToastRecord record = mToastQueue.get(index);
4196 try {
4197 record.callback.hide();
4198 } catch (RemoteException e) {
4199 Slog.w(TAG, "Object died trying to hide notification " + record.callback
4200 + " in package " + record.pkg);
4201 // don't worry about this, we're about to remove it from
4202 // the list anyway
4203 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004204
4205 ToastRecord lastToast = mToastQueue.remove(index);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07004206 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004207
4208 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004209 if (mToastQueue.size() > 0) {
4210 // Show the next one. If the callback fails, this will remove
4211 // it from the list, so don't assume that the list hasn't changed
4212 // after this point.
4213 showNextToastLocked();
4214 }
4215 }
4216
Julia Reynolds88860ce2017-06-01 16:55:49 -04004217 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004218 private void scheduleTimeoutLocked(ToastRecord r)
4219 {
4220 mHandler.removeCallbacksAndMessages(r);
4221 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4222 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4223 mHandler.sendMessageDelayed(m, delay);
4224 }
4225
4226 private void handleTimeout(ToastRecord record)
4227 {
4228 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4229 synchronized (mToastQueue) {
4230 int index = indexOfToastLocked(record.pkg, record.callback);
4231 if (index >= 0) {
4232 cancelToastLocked(index);
4233 }
4234 }
4235 }
4236
Julia Reynolds88860ce2017-06-01 16:55:49 -04004237 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004238 int indexOfToastLocked(String pkg, ITransientNotification callback)
4239 {
4240 IBinder cbak = callback.asBinder();
4241 ArrayList<ToastRecord> list = mToastQueue;
4242 int len = list.size();
4243 for (int i=0; i<len; i++) {
4244 ToastRecord r = list.get(i);
Beverly4ee785b2017-08-11 12:49:56 -04004245 if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4246 return i;
4247 }
4248 }
4249 return -1;
4250 }
4251
4252 @GuardedBy("mToastQueue")
4253 int indexOfToastPackageLocked(String pkg)
4254 {
4255 ArrayList<ToastRecord> list = mToastQueue;
4256 int len = list.size();
4257 for (int i=0; i<len; i++) {
4258 ToastRecord r = list.get(i);
4259 if (r.pkg.equals(pkg)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004260 return i;
4261 }
4262 }
4263 return -1;
4264 }
4265
Julia Reynolds88860ce2017-06-01 16:55:49 -04004266 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004267 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08004268 {
4269 int toastCount = 0; // toasts from this pid
4270 ArrayList<ToastRecord> list = mToastQueue;
4271 int N = list.size();
4272 for (int i=0; i<N; i++) {
4273 ToastRecord r = list.get(i);
4274 if (r.pid == pid) {
4275 toastCount++;
4276 }
4277 }
4278 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07004279 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08004280 } catch (RemoteException e) {
4281 // Shouldn't happen.
4282 }
4283 }
4284
Chris Wrenf9536642014-04-17 10:01:54 -04004285 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004286 if (!(message.obj instanceof RankingReconsideration)) return;
4287 RankingReconsideration recon = (RankingReconsideration) message.obj;
4288 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04004289 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004290 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004291 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4292 if (record == null) {
4293 return;
Chris Wrenf9536642014-04-17 10:01:54 -04004294 }
Chris Wren333a61c2014-05-28 16:40:57 -04004295 int indexBefore = findNotificationRecordIndexLocked(record);
4296 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004297 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004298 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04004299 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04004300 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04004301 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04004302 int indexAfter = findNotificationRecordIndexLocked(record);
4303 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004304 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004305 int visibilityAfter = record.getPackageVisibilityOverride();
4306 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4307 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004308 if (interceptBefore && !interceptAfter
4309 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04004310 buzzBeepBlinkLocked(record);
4311 }
Chris Wrenf9536642014-04-17 10:01:54 -04004312 }
Chris Wren333a61c2014-05-28 16:40:57 -04004313 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004314 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04004315 }
4316 }
4317
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004318 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04004319 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004320 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04004321 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004322 // Any field that can change via one of the extractors needs to be added here.
4323 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004324 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05004325 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004326 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4327 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4328 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4329 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04004330 for (int i = 0; i < N; i++) {
4331 final NotificationRecord r = mNotificationList.get(i);
4332 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004333 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05004334 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004335 channelBefore.add(r.getChannel());
4336 groupKeyBefore.add(r.getGroupKey());
4337 overridePeopleBefore.add(r.getPeopleOverride());
4338 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Chris Wren54bbef42014-07-09 18:37:56 -04004339 mRankingHelper.extractSignals(r);
4340 }
Chris Wren19a02b02015-12-22 10:34:22 -05004341 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04004342 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004343 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004344 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05004345 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004346 || showBadges[i] != r.canShowBadge()
4347 || !Objects.equals(channelBefore.get(i), r.getChannel())
4348 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4349 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
4350 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())) {
4351 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04004352 return;
4353 }
4354 }
4355 }
4356 }
4357
Julia Reynolds88860ce2017-06-01 16:55:49 -04004358 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004359 private void recordCallerLocked(NotificationRecord record) {
4360 if (mZenModeHelper.isCall(record)) {
4361 mZenModeHelper.recordCaller(record);
4362 }
4363 }
4364
Christoph Studerd5092bc2014-07-03 17:47:58 +02004365 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04004366 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04004367 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02004368 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004369 if (record.isIntercepted()) {
Julia Reynoldsd5607292016-02-05 15:25:58 -05004370 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4371 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4372 | (mZenModeHelper.shouldSuppressWhenScreenOn()
4373 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004374 record.setSuppressedVisualEffects(suppressed);
Julia Reynolds445cfa82017-05-08 15:41:45 -04004375 } else {
4376 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004377 }
Chris Wren333a61c2014-05-28 16:40:57 -04004378 }
4379
Julia Reynolds88860ce2017-06-01 16:55:49 -04004380 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04004381 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04004382 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04004383 }
4384
Chris Wrenf9536642014-04-17 10:01:54 -04004385 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004386 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04004387 mListeners.notifyRankingUpdateLocked();
Chris Wrenf9536642014-04-17 10:01:54 -04004388 }
4389 }
4390
John Spurlockd8afe3c2014-08-01 14:04:07 -04004391 private void scheduleListenerHintsChanged(int state) {
4392 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4393 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04004394 }
4395
Christoph Studer85a384b2014-08-27 20:16:15 +02004396 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4397 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4398 mHandler.obtainMessage(
4399 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4400 listenerInterruptionFilter,
4401 0).sendToTarget();
4402 }
4403
John Spurlockd8afe3c2014-08-01 14:04:07 -04004404 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004405 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004406 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004407 }
4408 }
4409
Christoph Studer85a384b2014-08-27 20:16:15 +02004410 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004411 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02004412 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4413 }
4414 }
4415
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004416 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08004417 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004418 public WorkerHandler(Looper looper) {
4419 super(looper);
4420 }
4421
Adam Lesinski182f73f2013-12-05 16:48:06 -08004422 @Override
4423 public void handleMessage(Message msg)
4424 {
4425 switch (msg.what)
4426 {
4427 case MESSAGE_TIMEOUT:
4428 handleTimeout((ToastRecord)msg.obj);
4429 break;
John Spurlock056c5192014-04-20 21:52:01 -04004430 case MESSAGE_SAVE_POLICY_FILE:
4431 handleSavePolicyFile();
4432 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004433 case MESSAGE_SEND_RANKING_UPDATE:
4434 handleSendRankingUpdate();
4435 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04004436 case MESSAGE_LISTENER_HINTS_CHANGED:
4437 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04004438 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02004439 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4440 handleListenerInterruptionFilterChanged(msg.arg1);
4441 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004442 }
4443 }
4444
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004445 protected void scheduleSendRankingUpdate() {
4446 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4447 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4448 sendMessage(m);
4449 }
4450 }
4451
Chris Wrenf9536642014-04-17 10:01:54 -04004452 }
4453
Chris Wren51017d02015-12-15 15:34:46 -05004454 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04004455 {
Chris Wren51017d02015-12-15 15:34:46 -05004456 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04004457 super(looper);
4458 }
4459
4460 @Override
4461 public void handleMessage(Message msg) {
4462 switch (msg.what) {
4463 case MESSAGE_RECONSIDER_RANKING:
4464 handleRankingReconsideration(msg);
4465 break;
Chris Wren51017d02015-12-15 15:34:46 -05004466 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004467 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04004468 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08004469 }
4470 }
Chris Wren51017d02015-12-15 15:34:46 -05004471
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004472 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05004473 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05004474 Message msg = Message.obtain();
4475 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05004476 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05004477 }
4478
4479 public void requestReconsideration(RankingReconsideration recon) {
4480 Message m = Message.obtain(this,
4481 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4482 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4483 sendMessageDelayed(m, delay);
4484 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004485 }
4486
Adam Lesinski182f73f2013-12-05 16:48:06 -08004487 // Notifications
4488 // ============================================================================
4489 static int clamp(int x, int low, int high) {
4490 return (x < low) ? low : ((x > high) ? high : x);
4491 }
4492
4493 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
4494 AccessibilityManager manager = AccessibilityManager.getInstance(getContext());
svetoslavganov75986cf2009-05-14 22:28:01 -07004495 if (!manager.isEnabled()) {
4496 return;
4497 }
4498
4499 AccessibilityEvent event =
4500 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4501 event.setPackageName(packageName);
4502 event.setClassName(Notification.class.getName());
4503 event.setParcelableData(notification);
4504 CharSequence tickerText = notification.tickerText;
4505 if (!TextUtils.isEmpty(tickerText)) {
4506 event.getText().add(tickerText);
4507 }
4508
4509 manager.sendAccessibilityEvent(event);
4510 }
4511
Julia Reynolds0839c022017-06-15 15:24:01 -04004512 /**
4513 * Removes all NotificationsRecords with the same key as the given notification record
4514 * from both lists. Do not call this method while iterating over either list.
4515 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004516 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04004517 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4518 // Remove from both lists, either list could have a separate Record for what is
4519 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004520 boolean wasPosted = false;
4521 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04004522 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4523 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004524 mNotificationList.remove(recordInList);
4525 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004526 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004527 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004528 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004529 != null) {
4530 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004531 }
Julia Reynolds0839c022017-06-15 15:24:01 -04004532 return wasPosted;
4533 }
4534
4535 @GuardedBy("mNotificationLock")
4536 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04004537 boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04004538 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004539
4540 // Record caller.
4541 recordCallerLocked(r);
4542
Joe Onorato46439ce2010-11-19 13:56:21 -08004543 // tell the app
4544 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004545 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08004546 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004547 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08004548 } catch (PendingIntent.CanceledException ex) {
4549 // do nothing - there's no relevant way to recover, and
4550 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04004551 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08004552 }
4553 }
4554 }
4555
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004556 // Only cancel these if this notification actually got to be posted.
4557 if (wasPosted) {
4558 // status bar
4559 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004560 if (reason != REASON_SNOOZED) {
4561 r.isCanceled = true;
4562 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004563 mListeners.notifyRemovedLocked(r.sbn, reason);
4564 mHandler.post(new Runnable() {
4565 @Override
4566 public void run() {
4567 mGroupHelper.onNotificationRemoved(r.sbn);
4568 }
4569 });
4570 }
4571
4572 // sound
4573 if (canceledKey.equals(mSoundNotificationKey)) {
4574 mSoundNotificationKey = null;
4575 final long identity = Binder.clearCallingIdentity();
4576 try {
4577 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4578 if (player != null) {
4579 player.stopAsync();
4580 }
4581 } catch (RemoteException e) {
4582 } finally {
4583 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004584 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004586
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004587 // vibrate
4588 if (canceledKey.equals(mVibrateNotificationKey)) {
4589 mVibrateNotificationKey = null;
4590 long identity = Binder.clearCallingIdentity();
4591 try {
4592 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07004593 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004594 finally {
4595 Binder.restoreCallingIdentity(identity);
4596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004599 // light
4600 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 }
4602
Christoph Studer546bec82014-03-14 12:17:12 +01004603 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04004604 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01004605 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04004606 case REASON_CANCEL:
4607 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01004608 case REASON_LISTENER_CANCEL:
4609 case REASON_LISTENER_CANCEL_ALL:
4610 mUsageStats.registerDismissedByUser(r);
4611 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05004612 case REASON_APP_CANCEL:
4613 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01004614 mUsageStats.registerRemovedByApp(r);
4615 break;
Christoph Studer546bec82014-03-14 12:17:12 +01004616 }
4617
Christoph Studer265c1052014-07-23 17:14:33 +02004618 String groupKey = r.getGroupKey();
4619 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004620 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02004621 mSummaryByGroupKey.remove(groupKey);
4622 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04004623 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
4624 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
4625 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04004626 }
Christoph Studercef37cf2014-07-25 14:18:17 +02004627
Daniel Sandler23d7c702013-03-07 16:32:06 -05004628 // Save it for users of getHistoricalNotifications()
4629 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02004630
Chris Wren6650e572015-05-15 17:19:25 -04004631 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -05004632 MetricsLogger.action(r.getLogMaker(now)
4633 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
4634 .setType(MetricsEvent.TYPE_DISMISS)
4635 .setSubtype(reason));
Chris Wrene6ddb8a2015-05-27 15:21:00 -04004636 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04004637 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004638 }
4639
4640 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07004641 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004642 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643 */
John Spurlocke6a7d932014-03-13 12:29:00 -04004644 void cancelNotification(final int callingUid, final int callingPid,
4645 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004646 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04004647 final int userId, final int reason, final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004648 // In enqueueNotificationInternal notifications are added by scheduling the
4649 // work on the worker handler. Hence, we also schedule the cancel on this
4650 // handler to avoid a scenario where an add notification call followed by a
4651 // remove notification call ends up in not removing the notification.
4652 mHandler.post(new Runnable() {
4653 @Override
4654 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02004655 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08004656 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
4657 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004658
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004659 synchronized (mNotificationLock) {
4660 // Look for the notification, searching both the posted and enqueued lists.
4661 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
4662 if (r != null) {
4663 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08004664
Christoph Studer546bec82014-03-14 12:17:12 +01004665 // Ideally we'd do this in the caller of this method. However, that would
4666 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04004667 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01004668 mUsageStats.registerClickedByUser(r);
4669 }
4670
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004671 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
4672 return;
4673 }
4674 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
4675 return;
4676 }
4677
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004678 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04004679 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004680 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02004681 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04004682 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004683 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004684 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004685 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004686 if (reason != REASON_SNOOZED) {
4687 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
4688 if (wasSnoozed) {
4689 savePolicyFile();
4690 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004691 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004692 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07004695 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004696 }
4697
4698 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07004699 * Determine whether the userId applies to the notification in question, either because
4700 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
4701 */
4702 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
4703 return
4704 // looking for USER_ALL notifications? match everything
4705 userId == UserHandle.USER_ALL
4706 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004707 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07004708 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004709 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07004710 }
4711
4712 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004713 * Determine whether the userId applies to the notification in question, either because
4714 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01004715 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004716 */
Kenny Guy2a764942014-04-02 13:29:20 +01004717 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00004718 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04004719 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00004720 }
4721
4722 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05004723 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004724 * {@code mustHaveFlags}.
4725 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004726 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004727 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04004728 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004729 mHandler.post(new Runnable() {
4730 @Override
4731 public void run() {
4732 String listenerName = listener == null ? null : listener.component.toShortString();
4733 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4734 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
4735 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004736
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004737 // Why does this parameter exist? Do we actually want to execute the above if doit
4738 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004739 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004740 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004741 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004742
4743 synchronized (mNotificationLock) {
4744 FlagChecker flagChecker = (int flags) -> {
4745 if ((flags & mustHaveFlags) != mustHaveFlags) {
4746 return false;
4747 }
4748 if ((flags & mustNotHaveFlags) != 0) {
4749 return false;
4750 }
4751 return true;
4752 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004753 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4754 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
4755 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04004756 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004757 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4758 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
4759 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04004760 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004761 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02004762 }
4763 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004764 });
4765 }
4766
4767 private interface FlagChecker {
4768 // Returns false if these flags do not pass the defined flag test.
4769 public boolean apply(int flags);
4770 }
4771
Julia Reynolds88860ce2017-06-01 16:55:49 -04004772 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004773 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
4774 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
4775 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04004776 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004777 ArrayList<NotificationRecord> canceledNotifications = null;
4778 for (int i = notificationList.size() - 1; i >= 0; --i) {
4779 NotificationRecord r = notificationList.get(i);
4780 if (includeCurrentProfiles) {
4781 if (!notificationMatchesCurrentProfiles(r, userId)) {
4782 continue;
4783 }
4784 } else if (!notificationMatchesUserId(r, userId)) {
4785 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004786 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004787 // Don't remove notifications to all, if there's no package name specified
4788 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
4789 continue;
4790 }
4791 if (!flagChecker.apply(r.getFlags())) {
4792 continue;
4793 }
4794 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
4795 continue;
4796 }
4797 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
4798 continue;
4799 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004800 if (canceledNotifications == null) {
4801 canceledNotifications = new ArrayList<>();
4802 }
Julia Reynolds0839c022017-06-15 15:24:01 -04004803 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04004804 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004805 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004806 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004807 }
4808 if (canceledNotifications != null) {
4809 final int M = canceledNotifications.size();
4810 for (int i = 0; i < M; i++) {
4811 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04004812 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004813 }
4814 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004815 }
4816 }
4817
Julia Reynolds50989772017-02-23 14:32:16 -05004818 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004819 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05004820 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004821 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05004822 return;
4823 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004824
Julia Reynolds79672302017-01-12 08:30:16 -05004825 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05004826 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
4827 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05004828 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004829 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004830 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05004831 }
4832
4833 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
4834 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05004835 if (DBG) {
4836 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
4837 }
Julia Reynolds79672302017-01-12 08:30:16 -05004838 mSnoozeHelper.repost(key);
4839 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05004840 }
4841
Julia Reynolds88860ce2017-06-01 16:55:49 -04004842 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07004843 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04004844 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004845 mHandler.post(new Runnable() {
4846 @Override
4847 public void run() {
4848 synchronized (mNotificationLock) {
4849 String listenerName =
4850 listener == null ? null : listener.component.toShortString();
4851 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
4852 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01004853
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004854 FlagChecker flagChecker = (int flags) -> {
4855 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
4856 != 0) {
4857 return false;
4858 }
4859 return true;
4860 };
4861
4862 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
4863 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
4864 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04004865 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004866 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
4867 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
4868 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04004869 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004870 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00004871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004872 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004873 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004874 }
4875
Christoph Studere4ef156b2014-07-04 18:41:57 +02004876 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04004877 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02004878 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04004879 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02004880 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02004881 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02004882 return;
4883 }
4884
4885 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02004886
4887 if (pkg == null) {
4888 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
4889 return;
4890 }
4891
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004892 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04004893 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004894 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04004895 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004896 }
4897
Julia Reynolds88860ce2017-06-01 16:55:49 -04004898 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004899 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
4900 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04004901 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004902 final String pkg = parentNotification.sbn.getPackageName();
4903 final int userId = parentNotification.getUserId();
4904 final int reason = REASON_GROUP_SUMMARY_CANCELED;
4905 for (int i = notificationList.size() - 1; i >= 0; i--) {
4906 final NotificationRecord childR = notificationList.get(i);
4907 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04004908 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004909 childR.getGroupKey().equals(parentNotification.getGroupKey())
Beverly40239d92017-07-07 10:20:41 -04004910 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
4911 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02004912 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
4913 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04004914 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04004915 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04004916 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02004917 }
4918 }
4919 }
4920
Julia Reynolds88860ce2017-06-01 16:55:49 -04004921 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004922 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004923 {
The Android Open Source Project10592532009-03-18 17:39:46 -07004924 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05004925 NotificationRecord ledNotification = null;
4926 while (ledNotification == null && !mLights.isEmpty()) {
4927 final String owner = mLights.get(mLights.size() - 1);
4928 ledNotification = mNotificationsByKey.get(owner);
4929 if (ledNotification == null) {
4930 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
4931 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004932 }
4933 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05004934
Mike Lockwood63b5ad92011-08-30 09:55:30 -04004935 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05004936 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05004937 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07004938 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004939 NotificationRecord.Light light = ledNotification.getLight();
4940 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05004941 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004942 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
4943 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05004944 }
The Android Open Source Project10592532009-03-18 17:39:46 -07004945 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004946 }
4947
Julia Reynolds88860ce2017-06-01 16:55:49 -04004948 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004949 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
4950 String groupKey, int userId) {
4951 List<NotificationRecord> records = new ArrayList<>();
4952 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
4953 records.addAll(
4954 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
4955 return records;
4956 }
4957
4958
Julia Reynolds88860ce2017-06-01 16:55:49 -04004959 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004960 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
4961 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
4962 List<NotificationRecord> records = new ArrayList<>();
4963 final int len = list.size();
4964 for (int i = 0; i < len; i++) {
4965 NotificationRecord r = list.get(i);
4966 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
4967 && r.sbn.getPackageName().equals(pkg)) {
4968 records.add(r);
4969 }
4970 }
4971 return records;
4972 }
4973
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004974 // Searches both enqueued and posted notifications by key.
4975 // TODO: need to combine a bunch of these getters with slightly different behavior.
4976 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04004977 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004978 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004979 NotificationRecord r;
4980 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
4981 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004982 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004983 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
4984 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004985 }
4986 return null;
4987 }
4988
Julia Reynolds88860ce2017-06-01 16:55:49 -04004989 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004990 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004991 NotificationRecord r;
4992 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
4993 return r;
4994 }
4995 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
4996 != null) {
4997 return r;
4998 }
4999 return null;
5000 }
5001
Julia Reynolds88860ce2017-06-01 16:55:49 -04005002 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005003 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005004 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005005 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005006 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005007 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01005008 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5009 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005010 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005011 }
5012 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005013 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005014 }
5015
Julia Reynolds88860ce2017-06-01 16:55:49 -04005016 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005017 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04005018 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005019 final int N = list.size();
5020 for (int i = 0; i < N; i++) {
5021 if (key.equals(list.get(i).getKey())) {
5022 return list.get(i);
5023 }
5024 }
5025 return null;
5026 }
5027
Julia Reynolds88860ce2017-06-01 16:55:49 -04005028 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02005029 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02005030 final int N = mNotificationList.size();
5031 for (int i = 0; i < N; i++) {
5032 if (key.equals(mNotificationList.get(i).getKey())) {
5033 return i;
5034 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02005035 }
Christoph Studerc5115552014-06-12 20:22:31 +02005036 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02005037 }
5038
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005039 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005040 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005041 updateLightsLocked();
5042 }
5043 }
John Spurlocke677d712014-02-13 12:52:19 -05005044
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005045 protected boolean isCallingUidSystem() {
5046 final int uid = Binder.getCallingUid();
5047 return uid == Process.SYSTEM_UID;
5048 }
5049
5050 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04005051 final int appid = UserHandle.getAppId(uid);
5052 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5053 }
John Spurlockb408e8e2014-04-23 21:12:45 -04005054
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005055 // TODO: Most calls should probably move to isCallerSystem.
5056 protected boolean isCallerSystemOrPhone() {
5057 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04005058 }
5059
Julia Reynoldsb852e562017-06-06 16:14:18 -04005060 private void checkCallerIsSystemOrShell() {
5061 if (Binder.getCallingUid() == Process.SHELL_UID) {
5062 return;
5063 }
5064 checkCallerIsSystem();
5065 }
5066
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005067 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005068 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005069 return;
5070 }
5071 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5072 }
5073
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005074 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005075 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005076 return;
5077 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04005078 checkCallerIsSameApp(pkg);
5079 }
5080
Chad Brubaker6b68f102017-01-27 13:39:00 -08005081 private boolean isCallerInstantApp(String pkg) {
5082 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005083 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08005084 return false;
5085 }
5086
5087 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5088
5089 try {
5090 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5091 UserHandle.getCallingUserId());
5092 if (ai == null) {
5093 throw new SecurityException("Unknown package " + pkg);
5094 }
5095 return ai.isInstantApp();
5096 } catch (RemoteException re) {
5097 throw new SecurityException("Unknown package " + pkg, re);
5098 }
5099
5100 }
5101
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005102 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04005103 final int uid = Binder.getCallingUid();
5104 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005105 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04005106 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04005107 if (ai == null) {
5108 throw new SecurityException("Unknown package " + pkg);
5109 }
John Spurlock7340fc82014-04-24 18:50:12 -04005110 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005111 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04005112 + pkg + " which is owned by uid " + ai.uid);
5113 }
5114 } catch (RemoteException re) {
5115 throw new SecurityException("Unknown package " + pkg + "\n" + re);
5116 }
5117 }
5118
John Spurlock32fe4c62014-10-02 12:16:02 -04005119 private static String callStateToString(int state) {
5120 switch (state) {
5121 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5122 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5123 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5124 default: return "CALL_STATE_UNKNOWN_" + state;
5125 }
5126 }
5127
5128 private void listenForCallState() {
5129 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5130 @Override
5131 public void onCallStateChanged(int state, String incomingNumber) {
5132 if (mCallState == state) return;
5133 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5134 mCallState = state;
5135 }
5136 }, PhoneStateListener.LISTEN_CALL_STATE);
5137 }
5138
Christoph Studer05ad4822014-05-16 14:16:03 +02005139 /**
5140 * Generates a NotificationRankingUpdate from 'sbns', considering only
5141 * notifications visible to the given listener.
5142 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005143 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005144 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04005145 final int N = mNotificationList.size();
5146 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02005147 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05005148 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04005149 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005150 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005151 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05005152 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005153 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05005154 Bundle overridePeople = new Bundle();
5155 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005156 Bundle showBadge = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04005157 for (int i = 0; i < N; i++) {
5158 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02005159 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005160 continue;
5161 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005162 final String key = record.sbn.getKey();
5163 keys.add(key);
5164 importance.add(record.getImportance());
5165 if (record.getImportanceExplanation() != null) {
5166 explanation.putCharSequence(key, record.getImportanceExplanation());
5167 }
Chris Wren333a61c2014-05-28 16:40:57 -04005168 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005169 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005170
Christoph Studer05ad4822014-05-16 14:16:03 +02005171 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005172 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005173 if (record.getPackageVisibilityOverride()
5174 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005175 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005176 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04005177 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05005178 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05005179 overridePeople.putStringArrayList(key, record.getPeopleOverride());
5180 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05005181 showBadge.putBoolean(key, record.canShowBadge());
Christoph Studer05ad4822014-05-16 14:16:03 +02005182 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005183 final int M = keys.size();
5184 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02005185 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05005186 int[] importanceAr = new int[M];
5187 for (int i = 0; i < M; i++) {
5188 importanceAr[i] = importance.get(i);
5189 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005190 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05005191 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Julia Reynolds924eed12017-01-19 09:52:07 -05005192 channels, overridePeople, snoozeCriteria, showBadge);
Christoph Studer05ad4822014-05-16 14:16:03 +02005193 }
5194
Julia Reynoldsda781472017-04-12 09:41:16 -04005195 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005196 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04005197 mCompanionManager = getCompanionManager();
5198 }
5199 // Companion mgr doesn't exist on all device types
5200 if (mCompanionManager == null) {
5201 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005202 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005203 long identity = Binder.clearCallingIdentity();
5204 try {
5205 List<String> associations = mCompanionManager.getAssociations(
5206 info.component.getPackageName(), info.userid);
5207 if (!ArrayUtils.isEmpty(associations)) {
5208 return true;
5209 }
5210 } catch (SecurityException se) {
5211 // Not a privileged listener
5212 } catch (RemoteException re) {
5213 Slog.e(TAG, "Cannot reach companion device service", re);
5214 } catch (Exception e) {
5215 Slog.e(TAG, "Cannot verify listener " + info, e);
5216 } finally {
5217 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005218 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005219 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005220 }
5221
Julia Reynolds727a7282017-04-13 10:54:01 -04005222 protected ICompanionDeviceManager getCompanionManager() {
5223 return ICompanionDeviceManager.Stub.asInterface(
5224 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5225 }
5226
Christoph Studercef37cf2014-07-25 14:18:17 +02005227 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5228 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5229 return false;
5230 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07005231 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02005232 return true;
5233 }
5234
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00005235 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005236 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005237 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005238 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005239 } catch (RemoteException re) {
5240 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00005241 } catch (IllegalArgumentException ex) {
5242 // Package not found.
5243 return false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005244 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005245 }
5246
Chris Wren47633422016-01-22 09:56:59 -05005247 private class TrimCache {
5248 StatusBarNotification heavy;
5249 StatusBarNotification sbnClone;
5250 StatusBarNotification sbnCloneLight;
5251
5252 TrimCache(StatusBarNotification sbn) {
5253 heavy = sbn;
5254 }
5255
5256 StatusBarNotification ForListener(ManagedServiceInfo info) {
5257 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5258 if (sbnCloneLight == null) {
5259 sbnCloneLight = heavy.cloneLight();
5260 }
5261 return sbnCloneLight;
5262 } else {
5263 if (sbnClone == null) {
5264 sbnClone = heavy.clone();
5265 }
5266 return sbnClone;
5267 }
5268 }
5269 }
5270
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005271 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005272 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05005273
Julia Reynoldsb852e562017-06-06 16:14:18 -04005274 public NotificationAssistants(IPackageManager pm) {
5275 super(getContext(), mNotificationLock, mUserProfiles, pm);
Chris Wren51017d02015-12-15 15:34:46 -05005276 }
5277
5278 @Override
5279 protected Config getConfig() {
5280 Config c = new Config();
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005281 c.caption = "notification assistant service";
5282 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005283 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005284 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5285 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05005286 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005287 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05005288 return c;
5289 }
5290
5291 @Override
5292 protected IInterface asInterface(IBinder binder) {
5293 return INotificationListener.Stub.asInterface(binder);
5294 }
5295
5296 @Override
5297 protected boolean checkType(IInterface service) {
5298 return service instanceof INotificationListener;
5299 }
5300
5301 @Override
5302 protected void onServiceAdded(ManagedServiceInfo info) {
5303 mListeners.registerGuestService(info);
5304 }
5305
5306 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005307 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05005308 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5309 mListeners.unregisterService(removed.service, removed.userid);
5310 }
Chris Wren47633422016-01-22 09:56:59 -05005311
5312 public void onNotificationEnqueued(final NotificationRecord r) {
5313 final StatusBarNotification sbn = r.sbn;
5314 TrimCache trimCache = new TrimCache(sbn);
5315
Chris Wren47633422016-01-22 09:56:59 -05005316 // There should be only one, but it's a list, so while we enforce
5317 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04005318 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05005319 boolean sbnVisible = isVisibleToListener(sbn, info);
5320 if (!sbnVisible) {
5321 continue;
5322 }
5323
5324 final int importance = r.getImportance();
5325 final boolean fromUser = r.isImportanceFromUser();
5326 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005327 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05005328 @Override
5329 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005330 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05005331 }
5332 });
5333 }
5334 }
5335
5336 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005337 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005338 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05005339 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5340 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005341 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05005342 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005343 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05005344 }
5345 }
5346
Julia Reynolds79672302017-01-12 08:30:16 -05005347 /**
5348 * asynchronously notify the assistant that a notification has been snoozed until a
5349 * context
5350 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005351 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05005352 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5353 final String snoozeCriterionId) {
5354 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04005355 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds79672302017-01-12 08:30:16 -05005356 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5357 mHandler.post(new Runnable() {
5358 @Override
5359 public void run() {
5360 final INotificationListener assistant =
5361 (INotificationListener) info.service;
5362 StatusBarNotificationHolder sbnHolder
5363 = new StatusBarNotificationHolder(sbnToPost);
5364 try {
5365 assistant.onNotificationSnoozedUntilContext(
5366 sbnHolder, snoozeCriterionId);
5367 } catch (RemoteException ex) {
5368 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5369 }
5370 }
5371 });
5372 }
5373 }
5374
Chris Wren47633422016-01-22 09:56:59 -05005375 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04005376 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05005377 }
Chris Wren51017d02015-12-15 15:34:46 -05005378 }
5379
John Spurlock7340fc82014-04-24 18:50:12 -04005380 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005381 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04005382
Christoph Studerb82bc782014-08-20 14:29:43 +02005383 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5384
Julia Reynoldsb852e562017-06-06 16:14:18 -04005385 public NotificationListeners(IPackageManager pm) {
5386 super(getContext(), mNotificationLock, mUserProfiles, pm);
5387
John Spurlock7340fc82014-04-24 18:50:12 -04005388 }
5389
5390 @Override
5391 protected Config getConfig() {
5392 Config c = new Config();
5393 c.caption = "notification listener";
5394 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005395 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04005396 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5397 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5398 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5399 c.clientLabel = R.string.notification_listener_binding_label;
5400 return c;
5401 }
5402
5403 @Override
5404 protected IInterface asInterface(IBinder binder) {
5405 return INotificationListener.Stub.asInterface(binder);
5406 }
5407
5408 @Override
Chris Wren51017d02015-12-15 15:34:46 -05005409 protected boolean checkType(IInterface service) {
5410 return service instanceof INotificationListener;
5411 }
5412
5413 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04005414 public void onServiceAdded(ManagedServiceInfo info) {
5415 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04005416 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005417 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04005418 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005419 }
John Spurlock7340fc82014-04-24 18:50:12 -04005420 try {
Chris Wren333a61c2014-05-28 16:40:57 -04005421 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04005422 } catch (RemoteException e) {
5423 // we tried
5424 }
5425 }
5426
John Spurlock1fa865f2014-07-21 14:56:39 -04005427 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005428 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04005429 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07005430 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005431 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01005432 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04005433 }
Christoph Studerb82bc782014-08-20 14:29:43 +02005434 mLightTrimListeners.remove(removed);
5435 }
5436
Julia Reynolds88860ce2017-06-01 16:55:49 -04005437 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02005438 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5439 if (trim == TRIM_LIGHT) {
5440 mLightTrimListeners.add(info);
5441 } else {
5442 mLightTrimListeners.remove(info);
5443 }
5444 }
5445
5446 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5447 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04005448 }
5449
John Spurlock7340fc82014-04-24 18:50:12 -04005450 /**
5451 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02005452 *
5453 * <p>
5454 * Also takes care of removing a notification that has been visible to a listener before,
5455 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04005456 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005457 @GuardedBy("mNotificationLock")
Christoph Studercef37cf2014-07-25 14:18:17 +02005458 public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) {
Christoph Studerb82bc782014-08-20 14:29:43 +02005459 // Lazily initialized snapshots of the notification.
Chris Wren47633422016-01-22 09:56:59 -05005460 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02005461
Julia Reynolds00314d92017-04-14 10:01:24 -04005462 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005463 boolean sbnVisible = isVisibleToListener(sbn, info);
5464 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5465 // This notification hasn't been and still isn't visible -> ignore.
5466 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005467 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005468 }
Chris Wren333a61c2014-05-28 16:40:57 -04005469 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02005470
5471 // This notification became invisible -> remove the old one.
5472 if (oldSbnVisible && !sbnVisible) {
5473 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5474 mHandler.post(new Runnable() {
5475 @Override
5476 public void run() {
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005477 notifyRemoved(info, oldSbnLightClone, update, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02005478 }
5479 });
Christoph Studer05ad4822014-05-16 14:16:03 +02005480 continue;
5481 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005482
Chris Wren47633422016-01-22 09:56:59 -05005483 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005484 mHandler.post(new Runnable() {
5485 @Override
5486 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02005487 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02005488 }
5489 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005490 }
5491 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005492
John Spurlock7340fc82014-04-24 18:50:12 -04005493 /**
5494 * asynchronously notify all listeners about a removed notification
5495 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005496 @GuardedBy("mNotificationLock")
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005497 public void notifyRemovedLocked(StatusBarNotification sbn, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04005498 // make a copy in case changes are made to the underlying Notification object
5499 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5500 // notification
5501 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04005502 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005503 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005504 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005505 }
Chris Wren333a61c2014-05-28 16:40:57 -04005506 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005507 mHandler.post(new Runnable() {
5508 @Override
5509 public void run() {
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005510 notifyRemoved(info, sbnLight, update, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02005511 }
5512 });
Chris Wrenf9536642014-04-17 10:01:54 -04005513 }
5514 }
5515
5516 /**
5517 * asynchronously notify all listeners about a reordering of notifications
Chris Wrenf9536642014-04-17 10:01:54 -04005518 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005519 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005520 public void notifyRankingUpdateLocked() {
Julia Reynolds00314d92017-04-14 10:01:24 -04005521 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005522 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5523 continue;
5524 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005525 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
John Spurlock7340fc82014-04-24 18:50:12 -04005526 mHandler.post(new Runnable() {
5527 @Override
5528 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -04005529 notifyRankingUpdate(serviceInfo, update);
John Spurlock7340fc82014-04-24 18:50:12 -04005530 }
5531 });
Kenny Guya263e4e2014-03-03 18:24:03 +00005532 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005533 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005534
Julia Reynolds88860ce2017-06-01 16:55:49 -04005535 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04005536 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005537 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04005538 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5539 continue;
5540 }
5541 mHandler.post(new Runnable() {
5542 @Override
5543 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005544 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005545 }
5546 });
5547 }
5548 }
5549
Christoph Studer85a384b2014-08-27 20:16:15 +02005550 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005551 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02005552 if (!serviceInfo.isEnabledForCurrentProfiles()) {
5553 continue;
5554 }
5555 mHandler.post(new Runnable() {
5556 @Override
5557 public void run() {
5558 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
5559 }
5560 });
5561 }
5562 }
5563
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005564 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005565 final NotificationChannel channel, final int modificationType) {
5566 if (channel == null) {
5567 return;
5568 }
5569 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04005570 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005571 continue;
5572 }
Julia Reynolds018aa622017-04-20 11:31:30 -04005573
Julia Reynoldsda781472017-04-12 09:41:16 -04005574 mHandler.post(new Runnable() {
5575 @Override
5576 public void run() {
Julia Reynolds018aa622017-04-20 11:31:30 -04005577 if (hasCompanionDevice(serviceInfo)) {
5578 notifyNotificationChannelChanged(
5579 serviceInfo, pkg, user, channel, modificationType);
5580 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005581 }
5582 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005583 }
5584 }
5585
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005586 protected void notifyNotificationChannelGroupChanged(
5587 final String pkg, final UserHandle user, final NotificationChannelGroup group,
5588 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005589 if (group == null) {
5590 return;
5591 }
5592 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04005593 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005594 continue;
5595 }
Julia Reynolds018aa622017-04-20 11:31:30 -04005596
Julia Reynoldsda781472017-04-12 09:41:16 -04005597 mHandler.post(new Runnable() {
5598 @Override
5599 public void run() {
Julia Reynolds018aa622017-04-20 11:31:30 -04005600 if (hasCompanionDevice(serviceInfo)) {
5601 notifyNotificationChannelGroupChanged(
5602 serviceInfo, pkg, user, group, modificationType);
5603 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005604 }
5605 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005606 }
5607 }
5608
Christoph Studercef37cf2014-07-25 14:18:17 +02005609 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02005610 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04005611 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005612 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04005613 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07005614 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04005615 } catch (RemoteException ex) {
5616 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
5617 }
5618 }
5619
Christoph Studercef37cf2014-07-25 14:18:17 +02005620 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005621 NotificationRankingUpdate rankingUpdate, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04005622 if (!info.enabledAndUserMatches(sbn.getUserId())) {
5623 return;
5624 }
Christoph Studer05ad4822014-05-16 14:16:03 +02005625 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005626 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04005627 try {
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -05005628 listener.onNotificationRemoved(sbnHolder, rankingUpdate, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04005629 } catch (RemoteException ex) {
5630 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04005631 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005632 }
Chris Wrenf9536642014-04-17 10:01:54 -04005633
Christoph Studer05ad4822014-05-16 14:16:03 +02005634 private void notifyRankingUpdate(ManagedServiceInfo info,
5635 NotificationRankingUpdate rankingUpdate) {
5636 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04005637 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02005638 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04005639 } catch (RemoteException ex) {
5640 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
5641 }
5642 }
John Spurlock1fa865f2014-07-21 14:56:39 -04005643
John Spurlockd8afe3c2014-08-01 14:04:07 -04005644 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04005645 final INotificationListener listener = (INotificationListener) info.service;
5646 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005647 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04005648 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005649 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04005650 }
5651 }
Justin Koh38156c52014-06-04 13:57:49 -07005652
Christoph Studer85a384b2014-08-27 20:16:15 +02005653 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
5654 int interruptionFilter) {
5655 final INotificationListener listener = (INotificationListener) info.service;
5656 try {
5657 listener.onInterruptionFilterChanged(interruptionFilter);
5658 } catch (RemoteException ex) {
5659 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
5660 }
5661 }
5662
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005663 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005664 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005665 final int modificationType) {
5666 final INotificationListener listener = (INotificationListener) info.service;
5667 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005668 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005669 } catch (RemoteException ex) {
5670 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
5671 }
5672 }
5673
5674 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005675 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005676 final int modificationType) {
5677 final INotificationListener listener = (INotificationListener) info.service;
5678 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04005679 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005680 } catch (RemoteException ex) {
5681 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
5682 }
5683 }
5684
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005685 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07005686 if (packageName == null) {
5687 return false;
5688 }
5689 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005690 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04005691 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07005692 if (packageName.equals(serviceInfo.component.getPackageName())) {
5693 return true;
5694 }
5695 }
5696 }
5697 return false;
5698 }
Kenny Guya263e4e2014-03-03 18:24:03 +00005699 }
John Spurlock25e2d242014-06-27 13:58:23 -04005700
5701 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04005702 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04005703 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04005704 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04005705 public long since;
5706 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04005707 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05005708 public boolean proto = false;
John Spurlock25e2d242014-06-27 13:58:23 -04005709
5710 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04005711 final DumpFilter filter = new DumpFilter();
5712 for (int ai = 0; ai < args.length; ai++) {
5713 final String a = args[ai];
Julia Reynoldsc9842c12017-02-07 12:46:41 -05005714 if ("--proto".equals(args[0])) {
5715 filter.proto = true;
5716 }
Dan Sandlera1770312015-07-10 13:59:29 -04005717 if ("--noredact".equals(a) || "--reveal".equals(a)) {
5718 filter.redact = false;
5719 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
5720 if (ai < args.length-1) {
5721 ai++;
5722 filter.pkgFilter = args[ai].trim().toLowerCase();
5723 if (filter.pkgFilter.isEmpty()) {
5724 filter.pkgFilter = null;
5725 } else {
5726 filter.filtered = true;
5727 }
5728 }
5729 } else if ("--zen".equals(a) || "zen".equals(a)) {
5730 filter.filtered = true;
5731 filter.zen = true;
5732 } else if ("--stats".equals(a)) {
5733 filter.stats = true;
5734 if (ai < args.length-1) {
5735 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01005736 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04005737 } else {
5738 filter.since = 0;
5739 }
5740 }
John Spurlock25e2d242014-06-27 13:58:23 -04005741 }
Dan Sandlera1770312015-07-10 13:59:29 -04005742 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04005743 }
5744
5745 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04005746 if (!filtered) return true;
5747 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04005748 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04005749 }
5750
5751 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04005752 if (!filtered) return true;
5753 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04005754 }
5755
5756 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04005757 if (!filtered) return true;
5758 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04005759 }
5760
5761 @Override
5762 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04005763 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04005764 }
5765 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07005766
5767 /**
5768 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
5769 * binder without sending large amounts of data over a oneway transaction.
5770 */
5771 private static final class StatusBarNotificationHolder
5772 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07005773 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005774
5775 public StatusBarNotificationHolder(StatusBarNotification value) {
5776 mValue = value;
5777 }
5778
Griff Hazene9aac5f2014-09-05 20:04:09 -07005779 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07005780 @Override
5781 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07005782 StatusBarNotification value = mValue;
5783 mValue = null;
5784 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07005785 }
5786 }
John Spurlock7c74f782015-06-04 13:01:42 -04005787
Julia Reynoldsb852e562017-06-06 16:14:18 -04005788 private class ShellCmd extends ShellCommand {
5789 public static final String USAGE = "help\n"
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005790 + "allow_listener COMPONENT\n"
5791 + "disallow_listener COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005792 + "set_assistant COMPONENT\n"
5793 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04005794 + "allow_dnd PACKAGE\n"
5795 + "disallow_dnd PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04005796
Julia Reynoldsb852e562017-06-06 16:14:18 -04005797 @Override
5798 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07005799 if (cmd == null) {
5800 return handleDefaultCommands(cmd);
5801 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005802 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04005803 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005804 switch (cmd) {
5805 case "allow_dnd": {
5806 getBinderService().setNotificationPolicyAccessGranted(
5807 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04005808 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04005809 break;
5810
5811 case "disallow_dnd": {
5812 getBinderService().setNotificationPolicyAccessGranted(
5813 getNextArgRequired(), false);
5814 }
5815 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005816 case "allow_listener": {
5817 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5818 if (cn == null) {
5819 pw.println("Invalid listener - must be a ComponentName");
5820 return -1;
5821 }
5822 getBinderService().setNotificationListenerAccessGranted(cn, true);
5823 }
5824 break;
5825 case "disallow_listener": {
5826 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5827 if (cn == null) {
5828 pw.println("Invalid listener - must be a ComponentName");
5829 return -1;
5830 }
5831 getBinderService().setNotificationListenerAccessGranted(cn, false);
5832 }
5833 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04005834 case "allow_assistant": {
5835 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5836 if (cn == null) {
5837 pw.println("Invalid assistant - must be a ComponentName");
5838 return -1;
5839 }
5840 getBinderService().setNotificationAssistantAccessGranted(cn, true);
5841 }
5842 break;
5843 case "disallow_assistant": {
5844 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
5845 if (cn == null) {
5846 pw.println("Invalid assistant - must be a ComponentName");
5847 return -1;
5848 }
5849 getBinderService().setNotificationAssistantAccessGranted(cn, false);
5850 }
5851 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04005852
5853 default:
5854 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04005855 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04005856 } catch (Exception e) {
5857 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04005858 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04005859 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04005860 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04005861 }
5862
Julia Reynoldsb852e562017-06-06 16:14:18 -04005863 @Override
5864 public void onHelp() {
5865 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04005866 }
5867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005868}