blob: d237aa2ca6bd99c331f534d65cf90658658852a7 [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 Reynoldsfc9767b2018-01-22 17:45:16 -050019import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050020import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
21import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040022import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040023import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040024import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050025import static android.content.pm.PackageManager.FEATURE_LEANBACK;
26import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynolds4db59552017-06-30 13:34:01 -040027import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040028import static android.os.UserHandle.USER_ALL;
Julia Reynolds88a879f2017-07-26 17:06:46 -040029import static android.os.UserHandle.USER_NULL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040030import static android.os.UserHandle.USER_SYSTEM;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040031import static android.service.notification.NotificationListenerService
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050032 .HINT_HOST_DISABLE_CALL_EFFECTS;
33import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
34import static android.service.notification.NotificationListenerService
35 .HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
36import static android.service.notification.NotificationListenerService
Julia Reynolds73ed76b2017-04-04 17:04:38 -040037 .NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
38import static android.service.notification.NotificationListenerService
39 .NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
40import static android.service.notification.NotificationListenerService
41 .NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050042import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
43import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040044import static android.service.notification.NotificationListenerService.REASON_CANCEL;
45import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050046import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040047import static android.service.notification.NotificationListenerService.REASON_CLICK;
48import static android.service.notification.NotificationListenerService.REASON_ERROR;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050049import static android.service.notification.NotificationListenerService
50 .REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050051import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
52import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
53import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
54import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
55import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
56import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
57import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050058import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050059import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
60import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Julia Reynoldsd5607292016-02-05 15:25:58 -050061import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF;
Julia Reynolds61721582016-01-05 08:35:25 -050062import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
Christoph Studerb82bc782014-08-20 14:29:43 +020063import static android.service.notification.NotificationListenerService.TRIM_FULL;
64import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070065import static android.view.Display.DEFAULT_DISPLAY;
66import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070067
Chris Wren51017d02015-12-15 15:34:46 -050068import android.Manifest;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -040069import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -080070import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -070071import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070072import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -050073import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -040074import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -050075import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -040076import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.app.IActivityManager;
78import android.app.INotificationManager;
79import android.app.ITransientNotification;
80import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -040081import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050082import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -050083import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050084import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.app.PendingIntent;
86import android.app.StatusBarManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050087import android.app.backup.BackupManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070088import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -070089import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -040090import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -070092import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040093import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -070094import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.content.Context;
96import android.content.Intent;
97import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040098import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +000099import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import android.content.pm.PackageManager;
101import android.content.pm.PackageManager.NameNotFoundException;
Christoph Studercee44ba2014-05-20 18:36:43 +0200102import android.content.pm.ParceledListSlice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700104import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400105import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700106import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500107import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700108import android.media.IRingtonePlayer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400111import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400112import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400113import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400115import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800117import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400118import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400119import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import android.os.Message;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400121import android.os.Parcelable;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700122import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700123import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400124import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400125import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400126import android.os.ShellCallback;
127import android.os.ShellCommand;
Chris Wrenc8673a82016-05-17 17:11:29 -0400128import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100129import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700130import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +0000131import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500132import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400134import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400135import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400136import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400137import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700138import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700139import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500140import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400141import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200142import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500143import android.service.notification.NotificationRecordProto;
144import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400145import android.service.notification.NotificationStats;
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500146import android.service.notification.NotifyingApp;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500147import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700148import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400149import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500150import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400151import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500152import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700153import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400154import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400155import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700156import android.util.AtomicFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157import android.util.Log;
Andy Stadler110988c2010-12-03 14:29:16 -0800158import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700159import android.util.SparseArray;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400160import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500161import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700162import android.view.accessibility.AccessibilityEvent;
163import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000165
Scott Greenwald9a05b312013-06-28 00:37:54 -0400166import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400167import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400168import com.android.internal.annotations.VisibleForTesting;
Chris Wren9eb5e102017-01-26 13:15:06 -0500169import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500170import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500171import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700172import com.android.internal.os.BackgroundThread;
Chris Wrend1dbc922015-06-19 17:51:16 -0400173import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400174import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600175import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400176import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400177import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400178import com.android.internal.util.XmlUtils;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700179import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800180import com.android.server.EventLogTags;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700181import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800182import com.android.server.SystemService;
183import com.android.server.lights.Light;
184import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400185import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500186import com.android.server.notification.ManagedServices.UserProfiles;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700187import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400188import com.android.server.statusbar.StatusBarManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100189import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800190
John Spurlockb408e8e2014-04-23 21:12:45 -0400191import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000192
Chris Wrene4b38802015-07-07 15:54:19 -0400193import org.json.JSONException;
194import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700195import org.xmlpull.v1.XmlPullParser;
196import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400197import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700198
John Spurlock35ef0a62015-05-28 11:24:10 -0400199import java.io.ByteArrayInputStream;
200import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400201import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400203import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400204import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400205import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400206import java.io.InputStream;
207import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100209import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500210import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000212import java.util.Arrays;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400213import java.util.HashSet;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500214import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400215import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200216import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500217import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400218import java.util.Set;
Chris Wren51017d02015-12-15 15:34:46 -0500219import java.util.concurrent.TimeUnit;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400220
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400221/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800222public class NotificationManagerService extends SystemService {
223 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100224 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800225 public static final boolean ENABLE_CHILD_NOTIFICATIONS
226 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
Adam Lesinski182f73f2013-12-05 16:48:06 -0800228 static final int MAX_PACKAGE_NOTIFICATIONS = 50;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400229 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 // message codes
Adam Lesinski182f73f2013-12-05 16:48:06 -0800232 static final int MESSAGE_TIMEOUT = 2;
John Spurlock056c5192014-04-20 21:52:01 -0400233 static final int MESSAGE_SAVE_POLICY_FILE = 3;
Chris Wren51017d02015-12-15 15:34:46 -0500234 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
235 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
236 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
237
238 // ranking thread messages
239 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
240 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700242 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800243 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800244
Adam Lesinski182f73f2013-12-05 16:48:06 -0800245 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200246
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500247 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
248
Adam Lesinski182f73f2013-12-05 16:48:06 -0800249 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
Adam Lesinski182f73f2013-12-05 16:48:06 -0800251 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500252
Adam Lesinski182f73f2013-12-05 16:48:06 -0800253 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400254
Christoph Studer12aeda82014-09-23 19:08:56 +0200255 // When #matchesCallFilter is called from the ringer, wait at most
256 // 3s to resolve the contacts. This timeout is required since
257 // ContactsProvider might take a long time to start up.
258 //
259 // Return STARRED_CONTACT when the timeout is hit in order to avoid
260 // missed calls in ZEN mode "Important".
261 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
262 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
263 ValidateNotificationPeople.STARRED_CONTACT;
264
Christoph Studer265c1052014-07-23 17:14:33 +0200265 /** notification_enqueue status value for a newly enqueued notification. */
266 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
267
268 /** notification_enqueue status value for an existing notification. */
269 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
270
271 /** notification_enqueue status value for an ignored notification. */
272 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400273 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200274
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500275 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
276
Julia Reynolds2a128742016-11-28 14:29:25 -0500277 private static final String ACTION_NOTIFICATION_TIMEOUT =
278 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
279 private static final int REQUEST_CODE_TIMEOUT = 1;
280 private static final String SCHEME_TIMEOUT = "timeout";
281 private static final String EXTRA_KEY = "key";
282
Adam Lesinski182f73f2013-12-05 16:48:06 -0800283 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400284 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500285 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500286 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800287 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500288 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800289 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800290 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700291 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500292 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400293 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400294 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800295 private IDeviceIdleController mDeviceIdleController;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400296 private IBinder mPermissionOwner;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400299 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400300 private final HandlerThread mRankingThread = new HandlerThread("ranker",
301 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302
Adam Lesinski182f73f2013-12-05 16:48:06 -0800303 private Light mNotificationLight;
304 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800305
Daniel Sandleredbb3802012-11-13 20:49:47 -0800306 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400307 private boolean mUseAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800308 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800309
John Spurlockd8afe3c2014-08-01 14:04:07 -0400310 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400311 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500312 private String mSoundNotificationKey;
313 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314
Bryce Lee7219ada2016-04-08 10:54:23 -0700315 private final SparseArray<ArraySet<ManagedServiceInfo>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400316 new SparseArray<>();
317 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400318 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500319 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400320
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500321 // for enabling and disabling notification pulse behavior
Mike Lockwood63b5ad92011-08-30 09:55:30 -0400322 private boolean mScreenOn = true;
Beverly5d463b62017-07-26 14:13:40 -0400323 protected boolean mInCall = false;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500324 private boolean mNotificationPulseEnabled;
325
Beverly5d463b62017-07-26 14:13:40 -0400326 private Uri mInCallNotificationUri;
327 private AudioAttributes mInCallNotificationAudioAttributes;
328 private float mInCallNotificationVolume;
Marta Białka39c992f2011-03-10 10:27:24 +0100329
Daniel Sandler09a247e2013-02-14 10:24:17 -0500330 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500331 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400332 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400333 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400334 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400335 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400336 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500337 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400338 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400339 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400340 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200341 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
Julia Reynolds7bcb57b2018-01-22 10:37:58 -0500342 final ArrayMap<Integer, ArrayList<NotifyingApp>> mRecentApps = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343
Chris Wren6054e612014-11-25 17:16:46 -0500344 // The last key in this list owns the hardware.
345 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700346
Adam Lesinski182f73f2013-12-05 16:48:06 -0800347 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700348 private UsageStatsManagerInternal mAppUsageStats;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500349
Griff Hazen9f637d12014-06-10 11:13:51 -0700350 private Archive mArchive;
351
John Spurlock21258a32015-05-27 18:22:55 -0400352 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400353 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400354
Daniel Sandler0da673f2012-04-11 12:33:16 -0400355 private static final int DB_VERSION = 1;
356
John Spurlock21258a32015-05-27 18:22:55 -0400357 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400358 private static final String ATTR_VERSION = "version";
359
Chris Wren54bbef42014-07-09 18:37:56 -0400360 private RankingHelper mRankingHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400361
John Spurlockb408e8e2014-04-23 21:12:45 -0400362 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400363 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400364 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400365 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200366 private NotificationUsageStats mUsageStats;
Christoph Studer546bec82014-03-14 12:17:12 +0100367
John Spurlocke6a7d932014-03-13 12:29:00 -0400368 private static final int MY_UID = Process.myUid();
369 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700370 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500371 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400372 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400373 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400374
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400375 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400376 private GroupHelper mGroupHelper;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500377 private boolean mIsTelevision;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400378
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500379 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700380 final int mBufferSize;
381 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500382
Griff Hazen9f637d12014-06-10 11:13:51 -0700383 public Archive(int size) {
384 mBufferSize = size;
385 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500386 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700387
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400388 public String toString() {
389 final StringBuilder sb = new StringBuilder();
390 final int N = mBuffer.size();
391 sb.append("Archive (");
392 sb.append(N);
393 sb.append(" notification");
394 sb.append((N==1)?")":"s)");
395 return sb.toString();
396 }
397
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500398 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700399 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500400 mBuffer.removeFirst();
401 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400402
403 // We don't want to store the heavy bits of the notification in the archive,
404 // but other clients in the system process might be using the object, so we
405 // store a (lightened) copy.
406 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500407 }
408
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500409 public Iterator<StatusBarNotification> descendingIterator() {
410 return mBuffer.descendingIterator();
411 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500412
413 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700414 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500415 final StatusBarNotification[] a
416 = new StatusBarNotification[Math.min(count, mBuffer.size())];
417 Iterator<StatusBarNotification> iter = descendingIterator();
418 int i=0;
419 while (iter.hasNext() && i < count) {
420 a[i++] = iter.next();
421 }
422 return a;
423 }
424
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500425 }
426
Julia Reynolds88a879f2017-07-26 17:06:46 -0400427 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400428 String defaultListenerAccess = getContext().getResources().getString(
429 com.android.internal.R.string.config_defaultListenerAccessPackages);
430 if (defaultListenerAccess != null) {
431 for (String whitelisted :
432 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
433 // Gather all notification listener components for candidate pkgs.
434 Set<ComponentName> approvedListeners =
435 mListeners.queryPackageForServices(whitelisted,
436 PackageManager.MATCH_DIRECT_BOOT_AWARE
437 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
438 for (ComponentName cn : approvedListeners) {
439 try {
440 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
441 userId, true);
442 } catch (RemoteException e) {
443 e.printStackTrace();
444 }
445 }
446 }
447 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500448
Julia Reynoldsb852e562017-06-06 16:14:18 -0400449 String defaultDndAccess = getContext().getResources().getString(
450 com.android.internal.R.string.config_defaultDndAccessPackages);
451 if (defaultListenerAccess != null) {
452 for (String whitelisted :
453 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
454 try {
455 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
456 } catch (RemoteException e) {
457 e.printStackTrace();
458 }
459 }
460 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500461
462 readDefaultAssistant(userId);
463 }
464
465 protected void readDefaultAssistant(int userId) {
466 String defaultAssistantAccess = getContext().getResources().getString(
467 com.android.internal.R.string.config_defaultAssistantAccessPackage);
468 if (defaultAssistantAccess != null) {
469 // Gather all notification assistant components for candidate pkg. There should
470 // only be one
471 Set<ComponentName> approvedAssistants =
472 mAssistants.queryPackageForServices(defaultAssistantAccess,
473 PackageManager.MATCH_DIRECT_BOOT_AWARE
474 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
475 for (ComponentName cn : approvedAssistants) {
476 try {
477 getBinderService().setNotificationAssistantAccessGrantedForUser(cn,
478 userId, true);
479 } catch (RemoteException e) {
480 e.printStackTrace();
481 }
482 }
483 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400484 }
485
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400486 void readPolicyXml(InputStream stream, boolean forRestore)
John Spurlock35ef0a62015-05-28 11:24:10 -0400487 throws XmlPullParserException, NumberFormatException, IOException {
488 final XmlPullParser parser = Xml.newPullParser();
489 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400490 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
491 boolean migratedManagedServices = false;
492 int outerDepth = parser.getDepth();
493 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
494 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
495 mZenModeHelper.readXml(parser, forRestore);
496 } else if (RankingHelper.TAG_RANKING.equals(parser.getName())){
497 mRankingHelper.readXml(parser, forRestore);
498 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400499 // No non-system managed services are allowed on low ram devices
Julia Reynoldse1816412017-10-24 10:39:11 -0400500 if (canUseManagedServices()) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400501 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
502 mListeners.readXml(parser);
503 migratedManagedServices = true;
504 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
505 mAssistants.readXml(parser);
506 migratedManagedServices = true;
507 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
508 mConditionProviders.readXml(parser);
509 migratedManagedServices = true;
510 }
Julia Reynolds68263d12017-06-21 14:21:19 -0400511 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400512 }
513
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400514 if (!migratedManagedServices) {
515 mListeners.migrateToXml();
516 mAssistants.migrateToXml();
517 mConditionProviders.migrateToXml();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400518 savePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400519 }
520 }
521
John Spurlock056c5192014-04-20 21:52:01 -0400522 private void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400523 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500524 synchronized (mPolicyFile) {
Daniel Sandler0da673f2012-04-11 12:33:16 -0400525
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400526 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400527 try {
528 infile = mPolicyFile.openRead();
John Spurlock35ef0a62015-05-28 11:24:10 -0400529 readPolicyXml(infile, false /*forRestore*/);
John Spurlock056c5192014-04-20 21:52:01 -0400530 } catch (FileNotFoundException e) {
531 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400532 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400533 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400534 } catch (IOException e) {
535 Log.wtf(TAG, "Unable to read notification policy", e);
536 } catch (NumberFormatException e) {
537 Log.wtf(TAG, "Unable to parse notification policy", e);
538 } catch (XmlPullParserException e) {
539 Log.wtf(TAG, "Unable to parse notification policy", e);
540 } finally {
541 IoUtils.closeQuietly(infile);
542 }
543 }
544 }
545
546 public void savePolicyFile() {
547 mHandler.removeMessages(MESSAGE_SAVE_POLICY_FILE);
548 mHandler.sendEmptyMessage(MESSAGE_SAVE_POLICY_FILE);
549 }
550
551 private void handleSavePolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400552 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
John Spurlock056c5192014-04-20 21:52:01 -0400553 synchronized (mPolicyFile) {
554 final FileOutputStream stream;
555 try {
556 stream = mPolicyFile.startWrite();
557 } catch (IOException e) {
558 Slog.w(TAG, "Failed to save policy file", e);
559 return;
560 }
561
562 try {
John Spurlock35ef0a62015-05-28 11:24:10 -0400563 writePolicyXml(stream, false /*forBackup*/);
John Spurlock056c5192014-04-20 21:52:01 -0400564 mPolicyFile.finishWrite(stream);
565 } catch (IOException e) {
566 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
567 mPolicyFile.failWrite(stream);
Daniel Sandler0da673f2012-04-11 12:33:16 -0400568 }
569 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400570 BackupManager.dataChanged(getContext().getPackageName());
571 }
572
573 private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
574 final XmlSerializer out = new FastXmlSerializer();
575 out.setOutput(stream, StandardCharsets.UTF_8.name());
576 out.startDocument(null, true);
577 out.startTag(null, TAG_NOTIFICATION_POLICY);
578 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
579 mZenModeHelper.writeXml(out, forBackup);
580 mRankingHelper.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400581 mListeners.writeXml(out, forBackup);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400582 mAssistants.writeXml(out, forBackup);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400583 mConditionProviders.writeXml(out, forBackup);
John Spurlock35ef0a62015-05-28 11:24:10 -0400584 out.endTag(null, TAG_NOTIFICATION_POLICY);
585 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400586 }
587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 private static final class ToastRecord
589 {
590 final int pid;
591 final String pkg;
Beverly4ee785b2017-08-11 12:49:56 -0400592 ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 int duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700594 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700596 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
597 Binder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 this.pid = pid;
599 this.pkg = pkg;
600 this.callback = callback;
601 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700602 this.token = token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
604
605 void update(int duration) {
606 this.duration = duration;
607 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800608
Beverly4ee785b2017-08-11 12:49:56 -0400609 void update(ITransientNotification callback) {
610 this.callback = callback;
611 }
612
John Spurlock25e2d242014-06-27 13:58:23 -0400613 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
614 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 pw.println(prefix + this);
616 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 @Override
619 public final String toString()
620 {
621 return "ToastRecord{"
622 + Integer.toHexString(System.identityHashCode(this))
623 + " pkg=" + pkg
624 + " callback=" + callback
625 + " duration=" + duration;
626 }
627 }
628
Beverly40239d92017-07-07 10:20:41 -0400629 @VisibleForTesting
630 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631
Adam Lesinski182f73f2013-12-05 16:48:06 -0800632 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500634 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400635 mDisableNotificationEffects =
636 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400637 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 // cancel whatever's going on
639 long identity = Binder.clearCallingIdentity();
640 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800641 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700642 if (player != null) {
643 player.stopAsync();
644 }
645 } catch (RemoteException e) {
646 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 Binder.restoreCallingIdentity(identity);
648 }
649
650 identity = Binder.clearCallingIdentity();
651 try {
652 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700653 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 Binder.restoreCallingIdentity(identity);
655 }
656 }
657 }
658 }
659
Adam Lesinski182f73f2013-12-05 16:48:06 -0800660 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400661 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500662 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400663 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000664 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 }
667
Adam Lesinski182f73f2013-12-05 16:48:06 -0800668 @Override
Christoph Studer03b87a22014-04-30 17:33:27 +0200669 public void onNotificationClick(int callingUid, int callingPid, String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800670 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500671 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200672 NotificationRecord r = mNotificationsByKey.get(key);
673 if (r == null) {
674 Log.w(TAG, "No notification with key: " + key);
675 return;
676 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400677 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500678 MetricsLogger.action(r.getLogMaker(now)
679 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
680 .setType(MetricsEvent.TYPE_ACTION));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400681 EventLogTags.writeNotificationClicked(key,
682 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
683
Christoph Studer03b87a22014-04-30 17:33:27 +0200684 StatusBarNotification sbn = r.sbn;
685 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
686 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
687 Notification.FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400688 REASON_CLICK, null);
Amith Yamasani7ec89412018-02-07 08:48:49 -0800689 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 }
692
Adam Lesinski182f73f2013-12-05 16:48:06 -0800693 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200694 public void onNotificationActionClick(int callingUid, int callingPid, String key,
695 int actionIndex) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800696 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500697 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200698 NotificationRecord r = mNotificationsByKey.get(key);
699 if (r == null) {
700 Log.w(TAG, "No notification with key: " + key);
701 return;
702 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400703 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500704 MetricsLogger.action(r.getLogMaker(now)
705 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
706 .setType(MetricsEvent.TYPE_ACTION)
707 .setSubtype(actionIndex));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400708 EventLogTags.writeNotificationActionClicked(key, actionIndex,
709 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Amith Yamasani7ec89412018-02-07 08:48:49 -0800710 reportUserInteraction(r);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200711 }
712 }
713
714 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400715 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400716 String pkg, String tag, int id, int userId, String key,
717 @NotificationStats.DismissalSurface int dismissalSurface) {
718 synchronized (mNotificationLock) {
719 NotificationRecord r = mNotificationsByKey.get(key);
720 if (r != null) {
721 r.recordDismissalSurface(dismissalSurface);
722 }
723 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400724 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000725 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400726 true, userId, REASON_CANCEL, null);
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400727 }
728
Adam Lesinski182f73f2013-12-05 16:48:06 -0800729 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400730 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500731 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400732 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400733 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100734 if (clearEffects) {
735 clearEffects();
736 }
737 }
738
739 @Override
740 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500741 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100742 EventLogTags.writeNotificationPanelHidden();
743 }
744
745 @Override
746 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500747 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100748 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400749 clearSoundLocked();
750 clearVibrateLocked();
751 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 }
753 }
Joe Onorato005847b2010-06-04 16:08:02 -0400754
Adam Lesinski182f73f2013-12-05 16:48:06 -0800755 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400756 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag, int id,
Kenny Guy3a7c4a52014-03-03 18:24:03 +0000757 int uid, int initialPid, String message, int userId) {
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400758 Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
759 + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
John Spurlocke6a7d932014-03-13 12:29:00 -0400760 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400761 REASON_ERROR, null);
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700762 long ident = Binder.clearCallingIdentity();
763 try {
Christopher Tate8aa8fe12017-01-20 17:50:32 -0800764 ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
Dianne Hackborn9d39d0c2010-06-24 15:57:42 -0700765 "Bad notification posted from package " + pkg
766 + ": " + message);
767 } catch (RemoteException e) {
768 }
769 Binder.restoreCallingIdentity(ident);
Joe Onorato005847b2010-06-04 16:08:02 -0400770 }
John Spurlocke677d712014-02-13 12:52:19 -0500771
772 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400773 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
774 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500775 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400776 for (NotificationVisibility nv : newlyVisibleKeys) {
777 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200778 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800779 if (!r.isSeen()) {
780 // Report to usage stats that notification was made visible
781 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
782 reportSeen(r);
783 }
Chris Wrend1dbc922015-06-19 17:51:16 -0400784 r.setVisibility(true, nv.rank);
785 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200786 }
787 // Note that we might receive this event after notifications
788 // have already left the system, e.g. after dismissing from the
789 // shade. Hence not finding notifications in
790 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400791 for (NotificationVisibility nv : noLongerVisibleKeys) {
792 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200793 if (r == null) continue;
Chris Wrend1dbc922015-06-19 17:51:16 -0400794 r.setVisibility(false, nv.rank);
795 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200796 }
797 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200798 }
Chris Wren78403d72014-07-28 10:23:24 +0100799
800 @Override
801 public void onNotificationExpansionChanged(String key,
802 boolean userAction, boolean expanded) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500803 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100804 NotificationRecord r = mNotificationsByKey.get(key);
805 if (r != null) {
806 r.stats.onExpansionChanged(userAction, expanded);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400807 final long now = System.currentTimeMillis();
Chris Wrenf7342712017-09-14 10:55:55 -0400808 if (userAction) {
Chris Wren377ac6d2017-09-12 14:15:23 -0400809 MetricsLogger.action(r.getLogMaker(now)
810 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
Chris Wrenf7342712017-09-14 10:55:55 -0400811 .setType(expanded ? MetricsEvent.TYPE_DETAIL
812 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400813 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500814 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400815 r.recordExpanded();
816 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400817 EventLogTags.writeNotificationExpansion(key,
818 userAction ? 1 : 0, expanded ? 1 : 0,
819 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
Chris Wren78403d72014-07-28 10:23:24 +0100820 }
821 }
822 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400823
824 @Override
825 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800826 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400827 synchronized (mNotificationLock) {
828 NotificationRecord r = mNotificationsByKey.get(key);
829 if (r != null) {
830 r.recordDirectReplied();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800831 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400832 }
833 }
834 }
835
836 @Override
837 public void onNotificationSettingsViewed(String key) {
838 synchronized (mNotificationLock) {
839 NotificationRecord r = mNotificationsByKey.get(key);
840 if (r != null) {
841 r.recordViewedSettings();
842 }
843 }
844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 };
846
Julia Reynolds88860ce2017-06-01 16:55:49 -0400847 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400848 private void clearSoundLocked() {
849 mSoundNotificationKey = null;
850 long identity = Binder.clearCallingIdentity();
851 try {
852 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
853 if (player != null) {
854 player.stopAsync();
855 }
856 } catch (RemoteException e) {
857 } finally {
858 Binder.restoreCallingIdentity(identity);
859 }
860 }
861
Julia Reynolds88860ce2017-06-01 16:55:49 -0400862 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400863 private void clearVibrateLocked() {
864 mVibrateNotificationKey = null;
865 long identity = Binder.clearCallingIdentity();
866 try {
867 mVibrator.cancel();
868 } finally {
869 Binder.restoreCallingIdentity(identity);
870 }
871 }
872
Julia Reynolds88860ce2017-06-01 16:55:49 -0400873 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -0400874 private void clearLightsLocked() {
875 // light
876 mLights.clear();
877 updateLightsLocked();
878 }
879
Beverlyd4f96492017-08-02 13:36:11 -0400880 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
881 @Override
882 public void onReceive(Context context, Intent intent) {
883 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
884 mZenModeHelper.updateDefaultZenRules();
Julia Reynolds816797a2017-08-11 15:47:09 -0400885 mRankingHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -0400886 }
887 }
888 };
889
Julia Reynoldsb852e562017-06-06 16:14:18 -0400890 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
891 @Override
892 public void onReceive(Context context, Intent intent) {
893 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
894 try {
895 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
896 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +0100897 int restoredFromSdkInt = intent.getIntExtra(
898 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400899 mListeners.onSettingRestored(
900 element, newValue, restoredFromSdkInt, getSendingUserId());
901 mConditionProviders.onSettingRestored(
902 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -0400903 } catch (Exception e) {
904 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
905 }
906 }
907 }
908 };
909
Julia Reynolds2a128742016-11-28 14:29:25 -0500910 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
911 @Override
912 public void onReceive(Context context, Intent intent) {
913 String action = intent.getAction();
914 if (action == null) {
915 return;
916 }
917 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
918 final NotificationRecord record;
919 synchronized (mNotificationLock) {
920 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
921 }
922 if (record != null) {
923 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
924 record.sbn.getPackageName(), record.sbn.getTag(),
925 record.sbn.getId(), 0,
926 Notification.FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
927 REASON_TIMEOUT, null);
928 }
929 }
930 }
931 };
932
Kenny Guy70058402014-10-28 20:45:06 +0000933 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 @Override
935 public void onReceive(Context context, Intent intent) {
936 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -0800937 if (action == null) {
938 return;
939 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800941 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -0400942 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -0400943 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -0400944 boolean cancelNotifications = true;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000945 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -0400946
Chris Wren3da73022013-05-10 14:41:21 -0400947 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -0400948 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800949 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -0400950 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800951 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000952 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
953 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
Kenny Guy70058402014-10-28 20:45:06 +0000954 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
955 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800956 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500957 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -0400958 boolean removingPackage = queryRemove &&
959 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
960 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800961 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800962 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500963 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +0000964 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
965 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
966 reason = REASON_PACKAGE_SUSPENDED;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800967 } else if (queryRestart) {
968 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -0500969 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800970 } else {
971 Uri uri = intent.getData();
972 if (uri == null) {
973 return;
974 }
975 String pkgName = uri.getSchemeSpecificPart();
976 if (pkgName == null) {
977 return;
978 }
Daniel Sandler26ece572012-06-01 15:38:46 -0400979 if (packageChanged) {
980 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -0700981 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500982 final int enabled = mPackageManager.getApplicationEnabledSetting(
983 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +0000984 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400985 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -0700986 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
987 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
988 cancelNotifications = false;
989 }
990 } catch (IllegalArgumentException e) {
991 // Package doesn't exist; probably racing with uninstall.
992 // cancelNotifications is already true, so nothing to do here.
993 if (DBG) {
994 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
995 }
Kenny Guy70058402014-10-28 20:45:06 +0000996 } catch (RemoteException e) {
997 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -0400998 }
999 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001000 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001001 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001003 if (pkgList != null && (pkgList.length > 0)) {
1004 for (String pkgName : pkgList) {
John Spurlock79f78922013-05-16 09:10:05 -04001005 if (cancelNotifications) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001006 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1007 !queryRestart, changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -04001008 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001009 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04001011 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001012 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001013 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001014 mRankingHelper.onPackagesChanged(removingPackage, changeUserId, pkgList, uidList);
1015 savePolicyFile();
Kenny Guy70058402014-10-28 20:45:06 +00001016 }
1017 }
1018 };
1019
1020 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1021 @Override
1022 public void onReceive(Context context, Intent intent) {
1023 String action = intent.getAction();
1024
1025 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001026 // Keep track of screen on/off state, but do not turn off the notification light
1027 // until user passes through the lock screen or views the notification.
1028 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001029 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001030 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1031 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001032 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001033 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
John Spurlock5d2eeb12014-01-16 10:46:36 -05001034 mInCall = TelephonyManager.EXTRA_STATE_OFFHOOK
1035 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001036 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001037 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1038 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1039 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001040 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001041 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001042 }
Rubin Xue95057a2016-04-01 16:49:25 +01001043 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001044 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001045 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001046 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001047 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001048 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001049 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1050 // turn off LED when user passes through lock screen
1051 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001052 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001053 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001054 // reload per-user settings
1055 mSettingsObserver.update(null);
John Spurlockb408e8e2014-04-23 21:12:45 -04001056 mUserProfiles.updateCache(context);
Christoph Studerb53dfd42014-09-12 14:45:59 +02001057 // Refresh managed services
John Spurlock1b8b22b2015-05-20 09:47:13 -04001058 mConditionProviders.onUserSwitched(user);
1059 mListeners.onUserSwitched(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001060 mAssistants.onUserSwitched(user);
John Spurlock21258a32015-05-27 18:22:55 -04001061 mZenModeHelper.onUserSwitched(user);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001062 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001063 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1064 if (userId != USER_NULL) {
1065 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001066 if (!mUserProfiles.isManagedProfile(userId)) {
1067 readDefaultApprovedServices(userId);
1068 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001069 }
John Spurlock21258a32015-05-27 18:22:55 -04001070 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001071 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001072 mUserProfiles.updateCache(context);
John Spurlock21258a32015-05-27 18:22:55 -04001073 mZenModeHelper.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001074 mRankingHelper.onUserRemoved(user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001075 mListeners.onUserRemoved(user);
1076 mConditionProviders.onUserRemoved(user);
1077 mAssistants.onUserRemoved(user);
Julia Reynolds2e9bf5f2017-05-03 13:23:30 -04001078 savePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001079 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001080 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001081 mConditionProviders.onUserUnlocked(user);
1082 mListeners.onUserUnlocked(user);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001083 mAssistants.onUserUnlocked(user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001084 mZenModeHelper.onUserUnlocked(user);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 }
1086 }
1087 };
1088
John Spurlock7c74f782015-06-04 13:01:42 -04001089 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001090 private final Uri NOTIFICATION_BADGING_URI
1091 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001092 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1093 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001094 private final Uri NOTIFICATION_RATE_LIMIT_URI
1095 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001096
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001097 SettingsObserver(Handler handler) {
1098 super(handler);
1099 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001100
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001101 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001102 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001103 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1104 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001105 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001106 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001107 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1108 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001109 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001110 }
1111
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001112 @Override public void onChange(boolean selfChange, Uri uri) {
1113 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001114 }
1115
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001116 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001117 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001118 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001119 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
1120 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT) != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001121 if (mNotificationPulseEnabled != pulseEnabled) {
1122 mNotificationPulseEnabled = pulseEnabled;
1123 updateNotificationPulse();
1124 }
1125 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001126 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1127 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1128 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1129 }
Chris Wren89aa2262017-05-05 18:05:56 -04001130 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
1131 mRankingHelper.updateBadgingEnabled();
1132 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001133 }
1134 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001135
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001136 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001137 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001138
Daniel Sandleredbb3802012-11-13 20:49:47 -08001139 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1140 int[] ar = r.getIntArray(resid);
1141 if (ar == null) {
1142 return def;
1143 }
1144 final int len = ar.length > maxlen ? maxlen : ar.length;
1145 long[] out = new long[len];
1146 for (int i=0; i<len; i++) {
1147 out[i] = ar[i];
1148 }
1149 return out;
1150 }
1151
Jeff Brownb880d882014-02-10 19:47:07 -08001152 public NotificationManagerService(Context context) {
1153 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001154 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001155 }
1156
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001157 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001158 @VisibleForTesting
1159 void setAudioManager(AudioManager audioMananger) {
1160 mAudioManager = audioMananger;
1161 }
1162
1163 @VisibleForTesting
1164 void setVibrator(Vibrator vibrator) {
1165 mVibrator = vibrator;
1166 }
1167
1168 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001169 void setLights(Light light) {
1170 mNotificationLight = light;
1171 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001172 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001173 }
1174
1175 @VisibleForTesting
1176 void setScreenOn(boolean on) {
1177 mScreenOn = on;
1178 }
1179
1180 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001181 int getNotificationRecordCount() {
1182 synchronized (mNotificationLock) {
1183 int count = mNotificationList.size() + mNotificationsByKey.size()
1184 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1185 // subtract duplicates
1186 for (NotificationRecord posted : mNotificationList) {
1187 if (mNotificationsByKey.containsKey(posted.getKey())) {
1188 count--;
1189 }
1190 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001191 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001192 }
1193 }
1194
1195 return count;
1196 }
1197 }
1198
Julia Reynolds7380d872018-01-12 10:28:26 -05001199 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001200 void clearNotifications() {
1201 mEnqueuedNotifications.clear();
1202 mNotificationList.clear();
1203 mNotificationsByKey.clear();
1204 mSummaryByGroupKey.clear();
1205 }
1206
Julia Reynolds080361e2017-07-13 11:23:12 -04001207 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001208 void addNotification(NotificationRecord r) {
1209 mNotificationList.add(r);
1210 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001211 if (r.sbn.isGroup()) {
1212 mSummaryByGroupKey.put(r.getGroupKey(), r);
1213 }
1214 }
1215
1216 @VisibleForTesting
1217 void addEnqueuedNotification(NotificationRecord r) {
1218 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001219 }
1220
1221 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001222 NotificationRecord getNotificationRecord(String key) {
1223 return mNotificationsByKey.get(key);
1224 }
1225
1226
1227 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001228 void setSystemReady(boolean systemReady) {
1229 mSystemReady = systemReady;
1230 }
1231
1232 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001233 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001234 mHandler = handler;
1235 }
1236
Chris Wrend4054312016-06-24 17:07:40 -04001237 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001238 void setFallbackVibrationPattern(long[] vibrationPattern) {
1239 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001240 }
1241
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001242 @VisibleForTesting
1243 void setPackageManager(IPackageManager packageManager) {
1244 mPackageManager = packageManager;
1245 }
1246
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001247 @VisibleForTesting
1248 void setRankingHelper(RankingHelper rankingHelper) {
1249 mRankingHelper = rankingHelper;
1250 }
1251
1252 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001253 void setRankingHandler(RankingHandler rankingHandler) {
1254 mRankingHandler = rankingHandler;
1255 }
1256
1257 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001258 void setIsTelevision(boolean isTelevision) {
1259 mIsTelevision = isTelevision;
1260 }
1261
Julia Reynolds76c096d2017-06-19 08:16:04 -04001262 @VisibleForTesting
1263 void setUsageStats(NotificationUsageStats us) {
1264 mUsageStats = us;
1265 }
1266
Julia Reynolds94187562017-10-10 13:58:49 -04001267 @VisibleForTesting
1268 void setAccessibilityManager(AccessibilityManager am) {
1269 mAccessibilityManager = am;
1270 }
1271
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001272 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001273 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001274 void init(Looper looper, IPackageManager packageManager,
1275 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001276 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001277 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001278 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001279 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001280 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am) {
Chris Wren54bbef42014-07-09 18:37:56 -04001281 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001282 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1283 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1284 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1285
Julia Reynolds94187562017-10-10 13:58:49 -04001286 mAccessibilityManager =
1287 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001288 mAm = am;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001289 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001290 mPackageManagerClient = packageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001291 mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
1292 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07001293 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Julia Reynolds2a128742016-11-28 14:29:25 -05001294 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001295 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001296 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001297 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1298 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001299 try {
1300 mPermissionOwner = mAm.newUriPermissionOwner("notification");
1301 } catch (RemoteException e) {
1302 Slog.w(TAG, "AM dead", e);
1303 }
San Mehat3ee13172010-02-04 20:54:43 -08001304
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001305 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001306 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001307 String[] extractorNames;
1308 try {
1309 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1310 } catch (Resources.NotFoundException e) {
1311 extractorNames = new String[0];
1312 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001313 mUsageStats = usageStats;
Chris Wren51017d02015-12-15 15:34:46 -05001314 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Chris Wren54bbef42014-07-09 18:37:56 -04001315 mRankingHelper = new RankingHelper(getContext(),
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001316 mPackageManagerClient,
Chris Wren51017d02015-12-15 15:34:46 -05001317 mRankingHandler,
Chris Wren5eab2b72015-06-16 13:56:22 -04001318 mUsageStats,
Chris Wren54bbef42014-07-09 18:37:56 -04001319 extractorNames);
Julia Reynoldsb852e562017-06-06 16:14:18 -04001320 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001321 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001322 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001323 @Override
1324 public void onConfigChanged() {
1325 savePolicyFile();
1326 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001327
1328 @Override
1329 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001330 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001331 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001332 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1333 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001334 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001335 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001336 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001337 }
1338 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001339
1340 @Override
1341 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001342 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
1343 }
John Spurlock056c5192014-04-20 21:52:01 -04001344 });
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001345 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001346 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001347
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001348 // This is a ManagedServices object that keeps track of the listeners.
1349 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001350
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001351 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001352 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001353
1354 mPolicyFile = policyFile;
1355 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001356
Adam Lesinski182f73f2013-12-05 16:48:06 -08001357 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001358 if (mStatusBar != null) {
1359 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001362 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1363 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001364
Daniel Sandleredbb3802012-11-13 20:49:47 -08001365 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001366 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001367 VIBRATE_PATTERN_MAXLEN,
1368 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001369 mInCallNotificationUri = Uri.parse("file://" +
1370 resources.getString(R.string.config_inCallNotificationSound));
1371 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1372 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1373 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001374 .build();
1375 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1376
Chris Wren5116a822014-06-04 15:59:50 -04001377 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
1378
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001379 // Don't start allowing notifications until the setup wizard has run once.
1380 // After that, including subsequent boots, init with notifications turned on.
1381 // This works on the first boot because the setup wizard will toggle this
1382 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001383 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001384 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001385 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001386 }
John Spurlockb2278d62015-04-07 12:47:12 -04001387 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001388 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001389
John Spurlockb408e8e2014-04-23 21:12:45 -04001390 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001391 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001392
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001393 mSettingsObserver = new SettingsObserver(mHandler);
1394
1395 mArchive = new Archive(resources.getInteger(
1396 R.integer.config_notificationServiceArchiveSize));
1397
1398 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1399 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
1400 }
1401
1402 @Override
1403 public void onStart() {
1404 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1405 @Override
1406 public void repost(int userId, NotificationRecord r) {
1407 try {
1408 if (DBG) {
1409 Slog.d(TAG, "Reposting " + r.getKey());
1410 }
1411 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1412 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1413 r.sbn.getNotification(), userId);
1414 } catch (Exception e) {
1415 Slog.e(TAG, "Cannot un-snooze notification", e);
1416 }
1417 }
1418 }, mUserProfiles);
1419
1420 final File systemDir = new File(Environment.getDataDirectory(), "system");
1421
1422 init(Looper.myLooper(),
1423 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1424 getLocalService(LightsManager.class),
1425 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001426 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1427 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001428 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1429 null, snoozeHelper, new NotificationUsageStats(getContext()),
Dianne Hackborne17b4452018-01-10 13:15:40 -08001430 new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001431 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001432 getGroupHelper(), ActivityManager.getService());
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001433
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001434 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001436 filter.addAction(Intent.ACTION_SCREEN_ON);
1437 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001438 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001439 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001440 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001441 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001442 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001443 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001444 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001445 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001446 getContext().registerReceiver(mIntentReceiver, filter);
Kenny Guy70058402014-10-28 20:45:06 +00001447
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001448 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001449 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001450 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001451 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001452 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1453 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1454 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001455 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1456 null);
1457
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001458 IntentFilter suspendedPkgFilter = new IntentFilter();
1459 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
1460 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1461 suspendedPkgFilter, null, null);
1462
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001463 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001464 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1465 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001466
Julia Reynolds2a128742016-11-28 14:29:25 -05001467 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1468 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1469 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1470
Julia Reynoldsb852e562017-06-06 16:14:18 -04001471 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1472 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1473
Beverlyd4f96492017-08-02 13:36:11 -04001474 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1475 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1476
Adam Lesinski182f73f2013-12-05 16:48:06 -08001477 publishBinderService(Context.NOTIFICATION_SERVICE, mService);
1478 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 }
1480
Julia Reynolds8aebf352017-06-26 11:35:33 -04001481 private GroupHelper getGroupHelper() {
1482 return new GroupHelper(new GroupHelper.Callback() {
1483 @Override
1484 public void addAutoGroup(String key) {
1485 synchronized (mNotificationLock) {
1486 addAutogroupKeyLocked(key);
1487 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001488 }
1489
1490 @Override
1491 public void removeAutoGroup(String key) {
1492 synchronized (mNotificationLock) {
1493 removeAutogroupKeyLocked(key);
1494 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001495 }
1496
1497 @Override
1498 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1499 createAutoGroupSummary(userId, pkg, triggeringKey);
1500 }
1501
1502 @Override
1503 public void removeAutoGroupSummary(int userId, String pkg) {
1504 synchronized (mNotificationLock) {
1505 clearAutogroupSummaryLocked(userId, pkg);
1506 }
1507 }
1508 });
1509 }
1510
John Spurlocke7a835b2015-05-13 10:47:05 -04001511 private void sendRegisteredOnlyBroadcast(String action) {
1512 getContext().sendBroadcastAsUser(new Intent(action)
1513 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL, null);
1514 }
1515
Adam Lesinski182f73f2013-12-05 16:48:06 -08001516 @Override
1517 public void onBootPhase(int phase) {
1518 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1519 // no beeping until we're basically done booting
1520 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001521
Adam Lesinski182f73f2013-12-05 16:48:06 -08001522 // Grab our optional AudioService
1523 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001524 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001525 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001526 mZenModeHelper.onSystemReady();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001527 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1528 // This observer will force an update when observe is called, causing us to
1529 // bind to listener services.
1530 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001531 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001532 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001533 mConditionProviders.onBootPhaseAppsCanStart();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 }
1535 }
1536
Julia Reynolds88860ce2017-06-01 16:55:49 -04001537 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001538 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001539 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001540 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001541 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001542 mListenerHints = hints;
1543 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001544 }
1545
Julia Reynolds88860ce2017-06-01 16:55:49 -04001546 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001547 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001548 final long updatedSuppressedEffects = calculateSuppressedEffects();
1549 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1550 final List<ComponentName> suppressors = getSuppressors();
1551 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1552 mEffectsSuppressors = suppressors;
1553 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001554 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001555 }
1556
Amith Yamasani396a10c2018-01-19 10:58:07 -08001557 private void exitIdle() {
1558 try {
1559 if (mDeviceIdleController != null) {
1560 mDeviceIdleController.exitIdle("notification interaction");
1561 }
1562 } catch (RemoteException e) {
1563 }
1564 }
1565
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001566 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1567 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001568 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1569 // cancel
1570 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001571 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001572 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001573 if (isUidSystemOrPhone(uid)) {
1574 int[] profileIds = mUserProfiles.getCurrentProfileIds();
1575 int N = profileIds.length;
1576 for (int i = 0; i < N; i++) {
1577 int profileId = profileIds[i];
1578 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1579 profileId, REASON_CHANNEL_BANNED,
1580 null);
1581 }
1582 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001583 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001584 final NotificationChannel preUpdate =
1585 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
1586
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001587 mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001588 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001589
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001590 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001591 final NotificationChannel modifiedChannel =
1592 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001593 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001594 pkg, UserHandle.getUserHandleForUid(uid),
1595 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001596 }
1597
Julia Reynolds924eed12017-01-19 09:52:07 -05001598 savePolicyFile();
1599 }
1600
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001601 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1602 NotificationChannel update) {
1603 try {
1604 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1605 && update.getImportance() != IMPORTANCE_NONE)
1606 || (preUpdate.getImportance() != IMPORTANCE_NONE
1607 && update.getImportance() == IMPORTANCE_NONE)) {
1608 getContext().sendBroadcastAsUser(
1609 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001610 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001611 update.getId())
1612 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1613 update.getImportance() == IMPORTANCE_NONE)
1614 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1615 .setPackage(pkg),
1616 UserHandle.of(UserHandle.getUserId(uid)), null);
1617 }
1618 } catch (SecurityException e) {
1619 Slog.w(TAG, "Can't notify app about channel change", e);
1620 }
1621 }
1622
Julia Reynolds005c8b92017-08-24 10:35:53 -04001623 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
1624 boolean fromApp, boolean fromListener) {
1625 Preconditions.checkNotNull(group);
1626 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001627
1628 final NotificationChannelGroup preUpdate =
1629 mRankingHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001630 mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
1631 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001632 if (!fromApp) {
1633 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
1634 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04001635 if (!fromListener) {
1636 mListeners.notifyNotificationChannelGroupChanged(pkg,
1637 UserHandle.of(UserHandle.getCallingUserId()), group,
1638 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
1639 }
1640 }
1641
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001642 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
1643 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
1644 try {
1645 if (preUpdate.isBlocked() != update.isBlocked()) {
1646 getContext().sendBroadcastAsUser(
1647 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001648 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001649 update.getId())
1650 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1651 update.isBlocked())
1652 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1653 .setPackage(pkg),
1654 UserHandle.of(UserHandle.getUserId(uid)), null);
1655 }
1656 } catch (SecurityException e) {
1657 Slog.w(TAG, "Can't notify app about group change", e);
1658 }
1659 }
1660
Bryce Lee7219ada2016-04-08 10:54:23 -07001661 private ArrayList<ComponentName> getSuppressors() {
1662 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
1663 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1664 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1665
1666 for (ManagedServiceInfo info : serviceInfoList) {
1667 names.add(info.component);
1668 }
1669 }
1670
1671 return names;
1672 }
1673
1674 private boolean removeDisabledHints(ManagedServiceInfo info) {
1675 return removeDisabledHints(info, 0);
1676 }
1677
1678 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
1679 boolean removed = false;
1680
1681 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1682 final int hint = mListenersDisablingEffects.keyAt(i);
1683 final ArraySet<ManagedServiceInfo> listeners =
1684 mListenersDisablingEffects.valueAt(i);
1685
1686 if (hints == 0 || (hint & hints) == hint) {
1687 removed = removed || listeners.remove(info);
1688 }
1689 }
1690
1691 return removed;
1692 }
1693
1694 private void addDisabledHints(ManagedServiceInfo info, int hints) {
1695 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1696 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
1697 }
1698
1699 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1700 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
1701 }
1702
1703 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1704 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
1705 }
1706 }
1707
1708 private void addDisabledHint(ManagedServiceInfo info, int hint) {
1709 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
1710 mListenersDisablingEffects.put(hint, new ArraySet<ManagedServiceInfo>());
1711 }
1712
1713 ArraySet<ManagedServiceInfo> hintListeners = mListenersDisablingEffects.get(hint);
1714 hintListeners.add(info);
1715 }
1716
1717 private int calculateHints() {
1718 int hints = 0;
1719 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
1720 int hint = mListenersDisablingEffects.keyAt(i);
1721 ArraySet<ManagedServiceInfo> serviceInfoList = mListenersDisablingEffects.valueAt(i);
1722
1723 if (!serviceInfoList.isEmpty()) {
1724 hints |= hint;
1725 }
1726 }
1727
1728 return hints;
1729 }
1730
1731 private long calculateSuppressedEffects() {
1732 int hints = calculateHints();
1733 long suppressedEffects = 0;
1734
1735 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
1736 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
1737 }
1738
1739 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
1740 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
1741 }
1742
1743 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
1744 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
1745 }
1746
1747 return suppressedEffects;
1748 }
1749
Julia Reynolds88860ce2017-06-01 16:55:49 -04001750 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02001751 private void updateInterruptionFilterLocked() {
1752 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
1753 if (interruptionFilter == mInterruptionFilter) return;
1754 mInterruptionFilter = interruptionFilter;
1755 scheduleInterruptionFilterChanged(interruptionFilter);
1756 }
1757
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001758 @VisibleForTesting
1759 INotificationManager getBinderService() {
1760 return INotificationManager.Stub.asInterface(mService);
1761 }
1762
Amith Yamasani7ec89412018-02-07 08:48:49 -08001763 /**
1764 * Report to usage stats that the notification was seen.
1765 * @param r notification record
1766 */
Amith Yamasani803eab692017-11-09 17:47:04 -08001767 protected void reportSeen(NotificationRecord r) {
1768 final int userId = r.sbn.getUserId();
1769 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001770 userId == UserHandle.USER_ALL ? USER_SYSTEM
Amith Yamasani803eab692017-11-09 17:47:04 -08001771 : userId,
1772 UsageEvents.Event.NOTIFICATION_SEEN);
1773 }
1774
Amith Yamasani7ec89412018-02-07 08:48:49 -08001775 /**
1776 * Report to usage stats that the notification was clicked.
1777 * @param r notification record
1778 */
1779 protected void reportUserInteraction(NotificationRecord r) {
1780 final int userId = r.sbn.getUserId();
1781 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
1782 userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId,
1783 UsageEvents.Event.USER_INTERACTION);
1784 }
1785
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04001786 @VisibleForTesting
1787 NotificationManagerInternal getInternalService() {
1788 return mInternalService;
1789 }
1790
Adam Lesinski182f73f2013-12-05 16:48:06 -08001791 private final IBinder mService = new INotificationManager.Stub() {
1792 // Toasts
1793 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001796 public void enqueueToast(String pkg, ITransientNotification callback, int duration)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001798 if (DBG) {
1799 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
1800 + " duration=" + duration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001801 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08001802
1803 if (pkg == null || callback == null) {
1804 Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
1805 return ;
1806 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001807 final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00001808 final boolean isPackageSuspended =
1809 isPackageSuspendedForUser(pkg, Binder.getCallingUid());
Adam Lesinski182f73f2013-12-05 16:48:06 -08001810
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001811 if (ENABLE_BLOCKED_TOASTS && !isSystemToast &&
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001812 (!areNotificationsEnabledForPackage(pkg, Binder.getCallingUid())
1813 || isPackageSuspended)) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04001814 Slog.e(TAG, "Suppressing toast from package " + pkg
1815 + (isPackageSuspended
1816 ? " due to package suspended by administrator."
1817 : " by user request."));
1818 return;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001819 }
1820
1821 synchronized (mToastQueue) {
1822 int callingPid = Binder.getCallingPid();
1823 long callingId = Binder.clearCallingIdentity();
1824 try {
1825 ToastRecord record;
Beverly4ee785b2017-08-11 12:49:56 -04001826 int index;
1827 // All packages aside from the android package can enqueue one toast at a time
1828 if (!isSystemToast) {
1829 index = indexOfToastPackageLocked(pkg);
1830 } else {
1831 index = indexOfToastLocked(pkg, callback);
1832 }
1833
1834 // If the package already has a toast, we update its toast
1835 // in the queue, we don't move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001836 if (index >= 0) {
1837 record = mToastQueue.get(index);
1838 record.update(duration);
Beverly4ee785b2017-08-11 12:49:56 -04001839 record.update(callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001840 } else {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001841 Binder token = new Binder();
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07001842 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001843 record = new ToastRecord(callingPid, pkg, callback, duration, token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001844 mToastQueue.add(record);
1845 index = mToastQueue.size() - 1;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001846 }
Beverly4ee785b2017-08-11 12:49:56 -04001847 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001848 // If it's at index 0, it's the current toast. It doesn't matter if it's
1849 // new or just been updated. Call back and tell it to show itself.
1850 // If the callback fails, this will remove it from the list, so don't
1851 // assume that it's valid after this.
1852 if (index == 0) {
1853 showNextToastLocked();
1854 }
1855 } finally {
1856 Binder.restoreCallingIdentity(callingId);
1857 }
1858 }
1859 }
1860
1861 @Override
1862 public void cancelToast(String pkg, ITransientNotification callback) {
1863 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
1864
1865 if (pkg == null || callback == null) {
1866 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
1867 return ;
1868 }
1869
1870 synchronized (mToastQueue) {
1871 long callingId = Binder.clearCallingIdentity();
1872 try {
1873 int index = indexOfToastLocked(pkg, callback);
1874 if (index >= 0) {
1875 cancelToastLocked(index);
1876 } else {
1877 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
1878 + " callback=" + callback);
1879 }
1880 } finally {
1881 Binder.restoreCallingIdentity(callingId);
1882 }
1883 }
1884 }
1885
1886 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001887 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001888 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04001889 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04001890 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001891 }
1892
1893 @Override
1894 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001895 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001896 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1897 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04001898 // Don't allow client applications to cancel foreground service notis or autobundled
1899 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001900 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
1901 (Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04001902 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04001903 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001904 }
1905
1906 @Override
1907 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04001908 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001909
1910 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
1911 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
1912
1913 // Calling from user space, don't allow the canceling of actively
1914 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04001915 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001916 pkg, null, 0, Notification.FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001917 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001918 }
1919
1920 @Override
1921 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
John Spurlock7340fc82014-04-24 18:50:12 -04001922 checkCallerIsSystem();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001923
Chris Wrenacf424a2016-03-15 12:48:55 -04001924 mRankingHelper.setEnabled(pkg, uid, enabled);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001925 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04001926 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001927 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
1928 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
1929 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05001930
1931 try {
1932 getContext().sendBroadcastAsUser(
1933 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
1934 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
1935 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1936 .setPackage(pkg),
1937 UserHandle.of(UserHandle.getUserId(uid)), null);
1938 } catch (SecurityException e) {
1939 Slog.w(TAG, "Can't notify app about app block change", e);
1940 }
1941
Chris Wrenacf424a2016-03-15 12:48:55 -04001942 savePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08001943 }
1944
1945 /**
1946 * Use this when you just want to know if notifications are OK for this package.
1947 */
1948 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001949 public boolean areNotificationsEnabled(String pkg) {
1950 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
1951 }
1952
1953 /**
1954 * Use this when you just want to know if notifications are OK for this package.
1955 */
1956 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08001957 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001958 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04001959
1960 return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001961 }
1962
Chris Wren54bbef42014-07-09 18:37:56 -04001963 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05001964 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001965 checkCallerIsSystemOrSameApp(pkg);
Julia Reynoldsef37f282016-02-12 09:11:27 -05001966 return mRankingHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05001967 }
1968
1969 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05001970 public boolean canShowBadge(String pkg, int uid) {
1971 checkCallerIsSystem();
1972 return mRankingHelper.canShowBadge(pkg, uid);
1973 }
1974
1975 @Override
1976 public void setShowBadge(String pkg, int uid, boolean showBadge) {
1977 checkCallerIsSystem();
1978 mRankingHelper.setShowBadge(pkg, uid, showBadge);
1979 savePolicyFile();
1980 }
1981
1982 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04001983 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
1984 NotificationChannelGroup group) throws RemoteException {
1985 enforceSystemOrSystemUI("Caller not system or systemui");
1986 createNotificationChannelGroup(pkg, uid, group, false, false);
1987 savePolicyFile();
1988 }
1989
1990 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05001991 public void createNotificationChannelGroups(String pkg,
1992 ParceledListSlice channelGroupList) throws RemoteException {
1993 checkCallerIsSystemOrSameApp(pkg);
1994 List<NotificationChannelGroup> groups = channelGroupList.getList();
1995 final int groupSize = groups.size();
1996 for (int i = 0; i < groupSize; i++) {
1997 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04001998 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05001999 }
2000 savePolicyFile();
2001 }
2002
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002003 private void createNotificationChannelsImpl(String pkg, int uid,
2004 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002005 List<NotificationChannel> channels = channelsList.getList();
2006 final int channelsSize = channels.size();
2007 for (int i = 0; i < channelsSize; i++) {
2008 final NotificationChannel channel = channels.get(i);
2009 Preconditions.checkNotNull(channel, "channel in list is null");
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002010 mRankingHelper.createNotificationChannel(pkg, uid, channel,
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002011 true /* fromTargetApp */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002012 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002013 UserHandle.getUserHandleForUid(uid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002014 mRankingHelper.getNotificationChannel(pkg, uid, channel.getId(), false),
2015 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002016 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002017 savePolicyFile();
2018 }
2019
2020 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002021 public void createNotificationChannels(String pkg,
2022 ParceledListSlice channelsList) throws RemoteException {
2023 checkCallerIsSystemOrSameApp(pkg);
2024 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2025 }
2026
2027 @Override
2028 public void createNotificationChannelsForPackage(String pkg, int uid,
2029 ParceledListSlice channelsList) throws RemoteException {
2030 checkCallerIsSystem();
2031 createNotificationChannelsImpl(pkg, uid, channelsList);
2032 }
2033
2034 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002035 public NotificationChannel getNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002036 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002037 return mRankingHelper.getNotificationChannel(
2038 pkg, Binder.getCallingUid(), channelId, false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002039 }
2040
2041 @Override
2042 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002043 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002044 checkCallerIsSystem();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002045 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002046 }
2047
2048 @Override
2049 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002050 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002051 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002052 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2053 throw new IllegalArgumentException("Cannot delete default channel");
2054 }
2055 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002056 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
2057 mRankingHelper.deleteNotificationChannel(pkg, callingUid, channelId);
2058 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002059 UserHandle.getUserHandleForUid(callingUid),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002060 mRankingHelper.getNotificationChannel(pkg, callingUid, channelId, true),
2061 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002062 savePolicyFile();
2063 }
2064
2065 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002066 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2067 checkCallerIsSystemOrSameApp(pkg);
2068 return mRankingHelper.getNotificationChannelGroupWithChannels(
2069 pkg, Binder.getCallingUid(), groupId, false);
2070 }
2071
2072 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002073 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2074 String pkg) {
2075 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002076 return mRankingHelper.getNotificationChannelGroups(
2077 pkg, Binder.getCallingUid(), false, false);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002078 }
2079
2080 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002081 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002082 checkCallerIsSystemOrSameApp(pkg);
2083
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002084 final int callingUid = Binder.getCallingUid();
2085 NotificationChannelGroup groupToDelete =
2086 mRankingHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
2087 if (groupToDelete != null) {
2088 List<NotificationChannel> deletedChannels =
2089 mRankingHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
2090 for (int i = 0; i < deletedChannels.size(); i++) {
2091 final NotificationChannel deletedChannel = deletedChannels.get(i);
2092 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2093 true,
2094 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2095 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002096 mListeners.notifyNotificationChannelChanged(pkg,
2097 UserHandle.getUserHandleForUid(callingUid),
2098 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002099 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2100 }
2101 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002102 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2103 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002104 savePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002105 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002106 }
2107
2108 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002109 public void updateNotificationChannelForPackage(String pkg, int uid,
2110 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002111 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002112 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002113 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002114 }
2115
2116 @Override
2117 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002118 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002119 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002120 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002121 }
2122
2123 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002124 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2125 boolean includeDeleted) {
2126 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
2127 return mRankingHelper.getNotificationChannels(pkg, uid, includeDeleted)
2128 .getList().size();
2129 }
2130
2131 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002132 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2133 enforceSystemOrSystemUI("onlyHasDefaultChannel");
2134 return mRankingHelper.onlyHasDefaultChannel(pkg, uid);
2135 }
2136
2137 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002138 public int getDeletedChannelCount(String pkg, int uid) {
2139 enforceSystemOrSystemUI("getDeletedChannelCount");
2140 return mRankingHelper.getDeletedChannelCount(pkg, uid);
2141 }
2142
2143 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002144 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2145 String pkg, int uid, boolean includeDeleted) {
2146 checkCallerIsSystem();
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002147 return mRankingHelper.getNotificationChannelGroups(pkg, uid, includeDeleted, true);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002148 }
2149
2150 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002151 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2152 String pkg, int uid, String groupId, boolean includeDeleted) {
2153 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
2154 return mRankingHelper.getNotificationChannelGroupWithChannels(
2155 pkg, uid, groupId, includeDeleted);
2156 }
2157
2158 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002159 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2160 String groupId, String pkg, int uid) {
2161 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
2162 return mRankingHelper.getNotificationChannelGroup(groupId, pkg, uid);
2163 }
2164
2165 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002166 public ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg) {
2167 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002168 return mRankingHelper.getNotificationChannels(
2169 pkg, Binder.getCallingUid(), false /* includeDeleted */);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002170 }
2171
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002172 @Override
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05002173 public ParceledListSlice<NotifyingApp> getRecentNotifyingAppsForUser(int userId) {
2174 checkCallerIsSystem();
2175 synchronized (mNotificationLock) {
2176 List<NotifyingApp> apps = new ArrayList<>(
2177 mRecentApps.getOrDefault(userId, new ArrayList<>()));
2178 return new ParceledListSlice<>(apps);
2179 }
2180 }
2181
2182 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002183 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002184 checkCallerIsSystem();
2185
2186 // Cancel posted notifications
2187 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2188 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2189
Julia Reynoldsb852e562017-06-06 16:14:18 -04002190 final String[] packages = new String[] {packageName};
2191 final int[] uids = new int[] {uid};
2192
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002193 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002194 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002195 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002196
2197 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002198 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002199
2200 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002201 if (!fromApp) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002202 mRankingHelper.onPackagesChanged(
2203 true, UserHandle.getCallingUserId(), packages, uids);
Julia Reynolds5355e852017-02-07 14:54:13 -05002204 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002205
2206 savePolicyFile();
2207 }
2208
2209
Adam Lesinski182f73f2013-12-05 16:48:06 -08002210 /**
2211 * System-only API for getting a list of current (i.e. not cleared) notifications.
2212 *
2213 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002214 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002215 */
2216 @Override
2217 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2218 // enforce() will ensure the calling uid has the correct permission
2219 getContext().enforceCallingOrSelfPermission(
2220 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2221 "NotificationManagerService.getActiveNotifications");
2222
2223 StatusBarNotification[] tmp = null;
2224 int uid = Binder.getCallingUid();
2225
2226 // noteOp will check to make sure the callingPkg matches the uid
2227 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2228 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002229 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002230 tmp = new StatusBarNotification[mNotificationList.size()];
2231 final int N = mNotificationList.size();
2232 for (int i=0; i<N; i++) {
2233 tmp[i] = mNotificationList.get(i).sbn;
2234 }
2235 }
2236 }
2237 return tmp;
2238 }
2239
2240 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002241 * Public API for getting a list of current notifications for the calling package/uid.
2242 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002243 * Note that since notification posting is done asynchronously, this will not return
2244 * notifications that are in the process of being posted.
2245 *
Dan Sandler994349c2015-04-15 11:02:54 -04002246 * @returns A list of all the package's notifications, in natural order.
2247 */
2248 @Override
2249 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2250 int incomingUserId) {
2251 checkCallerIsSystemOrSameApp(pkg);
2252 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2253 Binder.getCallingUid(), incomingUserId, true, false,
2254 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002255 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002256 final ArrayMap<String, StatusBarNotification> map
2257 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002258 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002259 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002260 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2261 mNotificationList.get(i).sbn);
2262 if (sbn != null) {
2263 map.put(sbn.getKey(), sbn);
2264 }
2265 }
2266 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2267 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2268 if (sbn != null) {
2269 map.put(sbn.getKey(), sbn);
2270 }
2271 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002272 final int M = mEnqueuedNotifications.size();
2273 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002274 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2275 mEnqueuedNotifications.get(i).sbn);
2276 if (sbn != null) {
2277 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04002278 }
2279 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002280 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
2281 list.addAll(map.values());
2282 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04002283 }
Dan Sandler994349c2015-04-15 11:02:54 -04002284 }
2285
Chris Wren6676dab2016-12-21 18:26:27 -05002286 private StatusBarNotification sanitizeSbn(String pkg, int userId,
2287 StatusBarNotification sbn) {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04002288 if (sbn.getPackageName().equals(pkg) && sbn.getUserId() == userId) {
Chris Wren6676dab2016-12-21 18:26:27 -05002289 // We could pass back a cloneLight() but clients might get confused and
2290 // try to send this thing back to notify() again, which would not work
2291 // very well.
2292 return new StatusBarNotification(
2293 sbn.getPackageName(),
2294 sbn.getOpPkg(),
Chris Wren6676dab2016-12-21 18:26:27 -05002295 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
2296 sbn.getNotification().clone(),
2297 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
2298 }
2299 return null;
2300 }
2301
Dan Sandler994349c2015-04-15 11:02:54 -04002302 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002303 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
2304 *
2305 * Requires ACCESS_NOTIFICATIONS which is signature|system.
2306 */
2307 @Override
2308 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
2309 // enforce() will ensure the calling uid has the correct permission
2310 getContext().enforceCallingOrSelfPermission(
2311 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2312 "NotificationManagerService.getHistoricalNotifications");
2313
2314 StatusBarNotification[] tmp = null;
2315 int uid = Binder.getCallingUid();
2316
2317 // noteOp will check to make sure the callingPkg matches the uid
2318 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2319 == AppOpsManager.MODE_ALLOWED) {
2320 synchronized (mArchive) {
2321 tmp = mArchive.getArray(count);
2322 }
2323 }
2324 return tmp;
2325 }
2326
2327 /**
2328 * Register a listener binder directly with the notification manager.
2329 *
2330 * Only works with system callers. Apps should extend
2331 * {@link android.service.notification.NotificationListenerService}.
2332 */
2333 @Override
2334 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05002335 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02002336 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05002337 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002338 }
2339
2340 /**
2341 * Remove a listener binder directly
2342 */
2343 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05002344 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05002345 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002346 }
2347
2348 /**
2349 * Allow an INotificationListener to simulate a "clear all" operation.
2350 *
2351 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
2352 *
2353 * @param token The binder for the listener, to check that the caller is allowed
2354 */
2355 @Override
John Spurlocka4294292014-03-24 18:02:32 -04002356 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002357 final int callingUid = Binder.getCallingUid();
2358 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002359 long identity = Binder.clearCallingIdentity();
2360 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002361 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002362 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
John Spurlocka4294292014-03-24 18:02:32 -04002363 if (keys != null) {
2364 final int N = keys.length;
2365 for (int i = 0; i < N; i++) {
2366 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07002367 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00002368 final int userId = r.sbn.getUserId();
2369 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04002370 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00002371 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04002372 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00002373 }
Griff Hazen335e1f02014-09-11 14:49:31 -07002374 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2375 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
2376 userId);
John Spurlocka4294292014-03-24 18:02:32 -04002377 }
2378 } else {
2379 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00002380 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04002381 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002382 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002383 } finally {
2384 Binder.restoreCallingIdentity(identity);
2385 }
2386 }
2387
Chris Wrenab41eec2016-01-04 18:01:27 -05002388 /**
2389 * Handle request from an approved listener to re-enable itself.
2390 *
2391 * @param component The componenet to be re-enabled, caller must match package.
2392 */
2393 @Override
2394 public void requestBindListener(ComponentName component) {
2395 checkCallerIsSystemOrSameApp(component.getPackageName());
2396 long identity = Binder.clearCallingIdentity();
2397 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04002398 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002399 mAssistants.isComponentEnabledForCurrentProfiles(component)
2400 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05002401 : mListeners;
2402 manager.setComponentState(component, true);
2403 } finally {
2404 Binder.restoreCallingIdentity(identity);
2405 }
2406 }
2407
2408 @Override
2409 public void requestUnbindListener(INotificationListener token) {
2410 long identity = Binder.clearCallingIdentity();
2411 try {
2412 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002413 synchronized (mNotificationLock) {
2414 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2415 info.getOwner().setComponentState(info.component, false);
2416 }
Chris Wrenab41eec2016-01-04 18:01:27 -05002417 } finally {
2418 Binder.restoreCallingIdentity(identity);
2419 }
2420 }
2421
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002422 @Override
2423 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002424 long identity = Binder.clearCallingIdentity();
2425 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002426 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002427 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2428 if (keys != null) {
2429 final int N = keys.length;
2430 for (int i = 0; i < N; i++) {
2431 NotificationRecord r = mNotificationsByKey.get(keys[i]);
2432 if (r == null) continue;
2433 final int userId = r.sbn.getUserId();
2434 if (userId != info.userid && userId != UserHandle.USER_ALL &&
2435 !mUserProfiles.isCurrentProfile(userId)) {
2436 throw new SecurityException("Disallowed call from listener: "
2437 + info.service);
2438 }
2439 if (!r.isSeen()) {
2440 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
Amith Yamasani803eab692017-11-09 17:47:04 -08002441 reportSeen(r);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07002442 r.setSeen();
2443 }
2444 }
2445 }
2446 }
2447 } finally {
2448 Binder.restoreCallingIdentity(identity);
2449 }
2450 }
2451
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002452 /**
2453 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2454 *
2455 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2456 *
Julia Reynolds79672302017-01-12 08:30:16 -05002457 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002458 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04002459 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04002460 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00002461 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04002462 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
2463 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
2464 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00002465 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04002466 }
2467
Adam Lesinski182f73f2013-12-05 16:48:06 -08002468 /**
Julia Reynolds79672302017-01-12 08:30:16 -05002469 * Allow an INotificationListener to snooze a single notification until a context.
2470 *
2471 * @param token The binder for the listener, to check that the caller is allowed
2472 */
2473 @Override
2474 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
2475 String key, String snoozeCriterionId) {
2476 long identity = Binder.clearCallingIdentity();
2477 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002478 synchronized (mNotificationLock) {
2479 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2480 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
2481 }
Julia Reynolds79672302017-01-12 08:30:16 -05002482 } finally {
2483 Binder.restoreCallingIdentity(identity);
2484 }
2485 }
2486
2487 /**
2488 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002489 *
2490 * @param token The binder for the listener, to check that the caller is allowed
2491 */
2492 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002493 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05002494 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002495 long identity = Binder.clearCallingIdentity();
2496 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002497 synchronized (mNotificationLock) {
2498 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2499 snoozeNotificationInt(key, duration, null, info);
2500 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04002501 } finally {
2502 Binder.restoreCallingIdentity(identity);
2503 }
2504 }
2505
2506 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002507 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002508 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002509 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002510 */
2511 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002512 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002513 long identity = Binder.clearCallingIdentity();
2514 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002515 synchronized (mNotificationLock) {
2516 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002517 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002518 unsnoozeNotificationInt(key, info);
2519 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05002520 } finally {
2521 Binder.restoreCallingIdentity(identity);
2522 }
2523 }
2524
2525 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002526 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
2527 *
2528 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
2529 *
2530 * @param token The binder for the listener, to check that the caller is allowed
2531 */
2532 @Override
2533 public void cancelNotificationFromListener(INotificationListener token, String pkg,
2534 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04002535 final int callingUid = Binder.getCallingUid();
2536 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002537 long identity = Binder.clearCallingIdentity();
2538 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002539 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002540 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00002541 if (info.supportsProfiles()) {
2542 Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
2543 + "from " + info.component
2544 + " use cancelNotification(key) instead.");
2545 } else {
2546 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
2547 pkg, tag, id, info.userid);
2548 }
Adam Lesinskie8240262014-03-26 16:01:00 -07002549 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002550 } finally {
2551 Binder.restoreCallingIdentity(identity);
2552 }
2553 }
2554
2555 /**
2556 * Allow an INotificationListener to request the list of outstanding notifications seen by
2557 * the current user. Useful when starting up, after which point the listener callbacks
2558 * should be used.
2559 *
2560 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002561 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04002562 * @returns The return value will contain the notifications specified in keys, in that
2563 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002564 */
2565 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02002566 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02002567 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002568 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04002569 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002570 final boolean getKeys = keys != null;
2571 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02002572 final ArrayList<StatusBarNotification> list
2573 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02002574 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04002575 final NotificationRecord r = getKeys
2576 ? mNotificationsByKey.get(keys[i])
2577 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02002578 if (r == null) continue;
2579 StatusBarNotification sbn = r.sbn;
2580 if (!isVisibleToListener(sbn, info)) continue;
2581 StatusBarNotification sbnToSend =
2582 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2583 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002584 }
Christoph Studercee44ba2014-05-20 18:36:43 +02002585 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002586 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002587 }
2588
Julia Reynoldscf63ff12017-01-24 13:55:48 -05002589 /**
2590 * Allow an INotificationListener to request the list of outstanding snoozed notifications
2591 * seen by the current user. Useful when starting up, after which point the listener
2592 * callbacks should be used.
2593 *
2594 * @param token The binder for the listener, to check that the caller is allowed
2595 * @returns The return value will contain the notifications specified in keys, in that
2596 * order, or if keys is null, all the notifications, in natural order.
2597 */
2598 @Override
2599 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
2600 INotificationListener token, int trim) {
2601 synchronized (mNotificationLock) {
2602 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2603 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
2604 final int N = snoozedRecords.size();
2605 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
2606 for (int i=0; i < N; i++) {
2607 final NotificationRecord r = snoozedRecords.get(i);
2608 if (r == null) continue;
2609 StatusBarNotification sbn = r.sbn;
2610 if (!isVisibleToListener(sbn, info)) continue;
2611 StatusBarNotification sbnToSend =
2612 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
2613 list.add(sbnToSend);
2614 }
2615 return new ParceledListSlice<>(list);
2616 }
2617 }
2618
Adam Lesinski182f73f2013-12-05 16:48:06 -08002619 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002620 public void requestHintsFromListener(INotificationListener token, int hints) {
2621 final long identity = Binder.clearCallingIdentity();
2622 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002623 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002624 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07002625 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
2626 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
2627 | HINT_HOST_DISABLE_CALL_EFFECTS;
2628 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04002629 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07002630 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002631 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07002632 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04002633 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002634 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04002635 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04002636 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04002637 } finally {
2638 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04002639 }
2640 }
2641
2642 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04002643 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002644 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04002645 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04002646 }
2647 }
2648
2649 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02002650 public void requestInterruptionFilterFromListener(INotificationListener token,
2651 int interruptionFilter) throws RemoteException {
2652 final long identity = Binder.clearCallingIdentity();
2653 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002654 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002655 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2656 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02002657 updateInterruptionFilterLocked();
2658 }
2659 } finally {
2660 Binder.restoreCallingIdentity(identity);
2661 }
2662 }
2663
2664 @Override
2665 public int getInterruptionFilterFromListener(INotificationListener token)
2666 throws RemoteException {
2667 synchronized (mNotificationLight) {
2668 return mInterruptionFilter;
2669 }
2670 }
2671
2672 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02002673 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
2674 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002675 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02002676 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
2677 if (info == null) return;
2678 mListeners.setOnNotificationPostedTrimLocked(info, trim);
2679 }
2680 }
2681
2682 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002683 public int getZenMode() {
2684 return mZenModeHelper.getZenMode();
2685 }
2686
2687 @Override
John Spurlock056c5192014-04-20 21:52:01 -04002688 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002689 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04002690 return mZenModeHelper.getConfig();
2691 }
2692
2693 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04002694 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002695 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05002696 final long identity = Binder.clearCallingIdentity();
2697 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002698 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05002699 } finally {
2700 Binder.restoreCallingIdentity(identity);
2701 }
2702 }
2703
2704 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002705 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002706 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05002707 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002708 }
2709
2710 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002711 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
2712 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002713 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002714 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002715 }
2716
2717 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002718 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002719 throws RemoteException {
2720 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2721 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2722 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2723 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002724 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002725
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002726 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
2727 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002728 }
2729
2730 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05002731 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002732 throws RemoteException {
2733 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
2734 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
2735 Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
2736 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
2737 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002738
Julia Reynolds361e82d32016-02-26 18:19:49 -05002739 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002740 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002741 }
2742
2743 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002744 public boolean removeAutomaticZenRule(String id) throws RemoteException {
2745 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002746 // Verify that they can modify zen rules.
2747 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
2748
Julia Reynolds4fe98d62015-10-06 16:23:41 -04002749 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002750 }
2751
2752 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05002753 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
2754 Preconditions.checkNotNull(packageName, "Package name is null");
2755 enforceSystemOrSystemUI("removeAutomaticZenRules");
2756
2757 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
2758 }
2759
2760 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05002761 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
2762 Preconditions.checkNotNull(owner, "Owner is null");
2763 enforceSystemOrSystemUI("getRuleInstanceCount");
2764
2765 return mZenModeHelper.getCurrentInstanceCount(owner);
2766 }
2767
2768 @Override
John Spurlock80774932015-05-07 17:38:50 -04002769 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
2770 enforcePolicyAccess(pkg, "setInterruptionFilter");
2771 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
2772 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
2773 final long identity = Binder.clearCallingIdentity();
2774 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04002775 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04002776 } finally {
2777 Binder.restoreCallingIdentity(identity);
2778 }
2779 }
2780
2781 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04002782 public void notifyConditions(final String pkg, IConditionProvider provider,
2783 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04002784 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2785 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04002786 mHandler.post(new Runnable() {
2787 @Override
2788 public void run() {
2789 mConditionProviders.notifyConditions(pkg, info, conditions);
2790 }
2791 });
John Spurlocke77bb362014-04-26 10:24:59 -04002792 }
2793
Julia Reynolds38e6ca42016-08-08 08:38:09 -04002794 @Override
2795 public void requestUnbindProvider(IConditionProvider provider) {
2796 long identity = Binder.clearCallingIdentity();
2797 try {
2798 // allow bound services to disable themselves
2799 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
2800 info.getOwner().setComponentState(info.component, false);
2801 } finally {
2802 Binder.restoreCallingIdentity(identity);
2803 }
2804 }
2805
2806 @Override
2807 public void requestBindProvider(ComponentName component) {
2808 checkCallerIsSystemOrSameApp(component.getPackageName());
2809 long identity = Binder.clearCallingIdentity();
2810 try {
2811 mConditionProviders.setComponentState(component, true);
2812 } finally {
2813 Binder.restoreCallingIdentity(identity);
2814 }
2815 }
2816
John Spurlocke77bb362014-04-26 10:24:59 -04002817 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002818 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04002819 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
2820 message);
John Spurlock7340fc82014-04-24 18:50:12 -04002821 }
2822
Julia Reynolds48034f82016-03-09 10:15:16 -05002823 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
2824 try {
2825 checkCallerIsSystemOrSameApp(pkg);
2826 } catch (SecurityException e) {
2827 getContext().enforceCallingPermission(
2828 android.Manifest.permission.STATUS_BAR_SERVICE,
2829 message);
2830 }
2831 }
2832
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002833 private void enforcePolicyAccess(int uid, String method) {
2834 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2835 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2836 return;
2837 }
2838 boolean accessAllowed = false;
2839 String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
2840 final int packageCount = packages.length;
2841 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002842 if (mConditionProviders.isPackageOrComponentAllowed(
2843 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04002844 accessAllowed = true;
2845 }
2846 }
2847 if (!accessAllowed) {
2848 Slog.w(TAG, "Notification policy access denied calling " + method);
2849 throw new SecurityException("Notification policy access denied");
2850 }
2851 }
2852
John Spurlock80774932015-05-07 17:38:50 -04002853 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04002854 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
2855 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
2856 return;
2857 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04002858 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002859 if (!checkPolicyAccess(pkg)) {
2860 Slog.w(TAG, "Notification policy access denied calling " + method);
2861 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04002862 }
2863 }
2864
John Spurlock80774932015-05-07 17:38:50 -04002865 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002866 return mConditionProviders.isPackageOrComponentAllowed(
2867 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04002868 }
2869
2870 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04002871 try {
2872 int uid = getContext().getPackageManager().getPackageUidAsUser(
2873 pkg, UserHandle.getCallingUserId());
2874 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
2875 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
2876 -1, true)) {
2877 return true;
2878 }
2879 } catch (NameNotFoundException e) {
2880 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002881 }
John Spurlock80774932015-05-07 17:38:50 -04002882 return checkPackagePolicyAccess(pkg) || mListeners.isComponentEnabledForPackage(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002883 }
2884
John Spurlock7340fc82014-04-24 18:50:12 -04002885 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002886 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06002887 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04002888 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Kweku Adams887f09c2017-11-13 17:12:20 -08002889 if (filter.stats) {
Chris Wrene4b38802015-07-07 15:54:19 -04002890 dumpJson(pw, filter);
Kweku Adams887f09c2017-11-13 17:12:20 -08002891 } else if (filter.proto) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05002892 dumpProto(fd, filter);
Chris Wrene4b38802015-07-07 15:54:19 -04002893 } else {
2894 dumpImpl(pw, filter);
2895 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002896 }
John Spurlockb4782522014-08-22 14:54:46 -04002897
2898 @Override
2899 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07002900 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04002901 }
John Spurlock2b122f42014-08-27 16:29:47 -04002902
2903 @Override
2904 public boolean matchesCallFilter(Bundle extras) {
2905 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02002906 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07002907 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02002908 extras,
2909 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
2910 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
2911 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04002912 }
John Spurlock530052a2014-11-30 16:26:19 -05002913
2914 @Override
2915 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05002916 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04002917 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05002918 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002919
Christopher Tatef9767d62015-04-08 14:35:43 -07002920 // Backup/restore interface
2921 @Override
2922 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05002923 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04002924 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002925 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04002926 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002927 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
2928 return null;
2929 }
songjinshi9bf22712017-02-04 10:47:45 +08002930 synchronized(mPolicyFile) {
2931 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
2932 try {
2933 writePolicyXml(baos, true /*forBackup*/);
2934 return baos.toByteArray();
2935 } catch (IOException e) {
2936 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
2937 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002938 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002939 return null;
2940 }
2941
2942 @Override
2943 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05002944 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04002945 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
2946 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
2947 if (payload == null) {
2948 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
2949 return;
2950 }
Xiaohui Chenddbe4ca2015-08-13 16:20:56 -07002951 //TODO: http://b/22388012
Julia Reynoldse0d711f2017-09-01 08:50:47 -04002952 if (user != USER_SYSTEM) {
John Spurlock35ef0a62015-05-28 11:24:10 -04002953 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
2954 return;
2955 }
songjinshi9bf22712017-02-04 10:47:45 +08002956 synchronized(mPolicyFile) {
2957 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
2958 try {
2959 readPolicyXml(bais, true /*forRestore*/);
2960 savePolicyFile();
2961 } catch (NumberFormatException | XmlPullParserException | IOException e) {
2962 Slog.w(TAG, "applyRestore: error reading payload", e);
2963 }
John Spurlock35ef0a62015-05-28 11:24:10 -04002964 }
Christopher Tatef9767d62015-04-08 14:35:43 -07002965 }
2966
John Spurlock1fc476d2015-04-14 16:05:20 -04002967 @Override
John Spurlock80774932015-05-07 17:38:50 -04002968 public boolean isNotificationPolicyAccessGranted(String pkg) {
2969 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04002970 }
2971
2972 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05002973 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
2974 enforceSystemOrSystemUIOrSamePackage(pkg,
2975 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04002976 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04002977 }
2978
2979 @Override
John Spurlock80774932015-05-07 17:38:50 -04002980 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
2981 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04002982 setNotificationPolicyAccessGrantedForUser(
2983 pkg, getCallingUserHandle().getIdentifier(), granted);
2984 }
2985
2986 @Override
2987 public void setNotificationPolicyAccessGrantedForUser(
2988 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04002989 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04002990 final long identity = Binder.clearCallingIdentity();
2991 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04002992 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04002993 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04002994 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04002995
Julia Reynoldse5c680f2017-09-13 09:25:10 -04002996 getContext().sendBroadcastAsUser(new Intent(
2997 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
2998 .setPackage(pkg)
2999 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003000 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003001 savePolicyFile();
3002 }
3003 } finally {
3004 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003005 }
John Spurlock80774932015-05-07 17:38:50 -04003006 }
3007
3008 @Override
3009 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003010 final long identity = Binder.clearCallingIdentity();
3011 try {
3012 return mZenModeHelper.getNotificationPolicy();
3013 } finally {
3014 Binder.restoreCallingIdentity(identity);
3015 }
3016 }
3017
Beverly6697eff2017-12-14 15:00:27 -05003018 /**
3019 * Sets the notification policy. Apps that target API levels below
3020 * {@link android.os.Build.VERSION_CODES#P} cannot make DND silence
3021 * {@link Policy#PRIORITY_CATEGORY_ALARMS} or
3022 * {@link Policy#PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER}
3023 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003024 @Override
John Spurlock80774932015-05-07 17:38:50 -04003025 public void setNotificationPolicy(String pkg, Policy policy) {
3026 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003027 final long identity = Binder.clearCallingIdentity();
3028 try {
Beverly6697eff2017-12-14 15:00:27 -05003029 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3030 0, UserHandle.getUserId(MY_UID));
3031
3032 if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.O_MR1) {
3033 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
3034
3035 int priorityCategories = policy.priorityCategories
3036 | (currPolicy.priorityCategories & Policy.PRIORITY_CATEGORY_ALARMS)
3037 | (currPolicy.priorityCategories &
3038 Policy.PRIORITY_CATEGORY_MEDIA_SYSTEM_OTHER);
3039 policy = new Policy(priorityCategories,
3040 policy.priorityCallSenders, policy.priorityMessageSenders,
3041 policy.suppressedVisualEffects);
3042 }
3043
John Spurlock1fc476d2015-04-14 16:05:20 -04003044 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003045 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003046 } finally {
3047 Binder.restoreCallingIdentity(identity);
3048 }
3049 }
Chris Wren51017d02015-12-15 15:34:46 -05003050
3051 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003052 public List<String> getEnabledNotificationListenerPackages() {
3053 checkCallerIsSystem();
3054 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3055 }
3056
3057 @Override
3058 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3059 checkCallerIsSystem();
3060 return mListeners.getAllowedComponents(userId);
3061 }
3062
3063 @Override
3064 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3065 Preconditions.checkNotNull(listener);
3066 checkCallerIsSystemOrSameApp(listener.getPackageName());
3067 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3068 getCallingUserHandle().getIdentifier());
3069 }
3070
3071 @Override
3072 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3073 int userId) {
3074 Preconditions.checkNotNull(listener);
3075 checkCallerIsSystem();
3076 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3077 userId);
3078 }
3079
3080 @Override
3081 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3082 Preconditions.checkNotNull(assistant);
3083 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003084 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003085 getCallingUserHandle().getIdentifier());
3086 }
3087
3088 @Override
3089 public void setNotificationListenerAccessGranted(ComponentName listener,
3090 boolean granted) throws RemoteException {
3091 setNotificationListenerAccessGrantedForUser(
3092 listener, getCallingUserHandle().getIdentifier(), granted);
3093 }
3094
3095 @Override
3096 public void setNotificationAssistantAccessGranted(ComponentName assistant,
3097 boolean granted) throws RemoteException {
3098 setNotificationAssistantAccessGrantedForUser(
3099 assistant, getCallingUserHandle().getIdentifier(), granted);
3100 }
3101
3102 @Override
3103 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
3104 boolean granted) throws RemoteException {
3105 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003106 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003107 final long identity = Binder.clearCallingIdentity();
3108 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04003109 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003110 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3111 userId, false, granted);
3112 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3113 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003114
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003115 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds92febc32017-10-26 11:30:31 -04003116 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003117 .setPackage(listener.getPackageName())
3118 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003119 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003120
3121 savePolicyFile();
3122 }
3123 } finally {
3124 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003125 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003126 }
3127
3128 @Override
3129 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
3130 int userId, boolean granted) throws RemoteException {
3131 Preconditions.checkNotNull(assistant);
Julia Reynolds0d217642017-08-11 11:26:04 -04003132 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003133 final long identity = Binder.clearCallingIdentity();
3134 try {
Julia Reynoldse1816412017-10-24 10:39:11 -04003135 if (canUseManagedServices()) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003136 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
3137 userId, false, granted);
3138 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
3139 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003140
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003141 getContext().sendBroadcastAsUser(new Intent(
3142 NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
3143 .setPackage(assistant.getPackageName())
3144 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003145 UserHandle.of(userId), null);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003146
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003147 savePolicyFile();
3148 }
3149 } finally {
3150 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003151 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003152 }
3153
3154 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003155 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
3156 Adjustment adjustment) throws RemoteException {
3157 final long identity = Binder.clearCallingIdentity();
3158 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003159 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003160 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003161 int N = mEnqueuedNotifications.size();
3162 for (int i = 0; i < N; i++) {
3163 final NotificationRecord n = mEnqueuedNotifications.get(i);
3164 if (Objects.equals(adjustment.getKey(), n.getKey())
3165 && Objects.equals(adjustment.getUser(), n.getUserId())) {
3166 applyAdjustment(n, adjustment);
3167 break;
3168 }
3169 }
3170 }
3171 } finally {
3172 Binder.restoreCallingIdentity(identity);
3173 }
3174 }
3175
3176 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003177 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003178 Adjustment adjustment) throws RemoteException {
Chris Wren51017d02015-12-15 15:34:46 -05003179 final long identity = Binder.clearCallingIdentity();
3180 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003181 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003182 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003183 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3184 applyAdjustment(n, adjustment);
Chris Wren51017d02015-12-15 15:34:46 -05003185 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003186 mRankingHandler.requestSort();
Julia Reynoldse46bb372016-03-17 11:05:58 -04003187 } finally {
3188 Binder.restoreCallingIdentity(identity);
3189 }
3190 }
3191
3192 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003193 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynoldse46bb372016-03-17 11:05:58 -04003194 List<Adjustment> adjustments) throws RemoteException {
3195
3196 final long identity = Binder.clearCallingIdentity();
3197 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003198 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003199 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003200 for (Adjustment adjustment : adjustments) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003201 NotificationRecord n = mNotificationsByKey.get(adjustment.getKey());
3202 applyAdjustment(n, adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003203 }
3204 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003205 mRankingHandler.requestSort();
Chris Wren51017d02015-12-15 15:34:46 -05003206 } finally {
3207 Binder.restoreCallingIdentity(identity);
3208 }
3209 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003210
3211 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04003212 public void updateNotificationChannelGroupFromPrivilegedListener(
3213 INotificationListener token, String pkg, UserHandle user,
3214 NotificationChannelGroup group) throws RemoteException {
3215 Preconditions.checkNotNull(user);
3216 verifyPrivilegedListener(token, user);
3217 createNotificationChannelGroup(
3218 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
3219 savePolicyFile();
3220 }
3221
3222 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003223 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003224 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003225 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003226 Preconditions.checkNotNull(pkg);
3227 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003228
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003229 verifyPrivilegedListener(token, user);
3230 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003231 }
3232
3233 @Override
3234 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003235 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3236 Preconditions.checkNotNull(pkg);
3237 Preconditions.checkNotNull(user);
3238 verifyPrivilegedListener(token, user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003239
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003240 return mRankingHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
3241 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003242 }
3243
3244 @Override
3245 public ParceledListSlice<NotificationChannelGroup>
3246 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003247 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
3248 Preconditions.checkNotNull(pkg);
3249 Preconditions.checkNotNull(user);
3250 verifyPrivilegedListener(token, user);
3251
3252 List<NotificationChannelGroup> groups = new ArrayList<>();
3253 groups.addAll(mRankingHelper.getNotificationChannelGroups(
3254 pkg, getUidForPackageAndUser(pkg, user)));
3255 return new ParceledListSlice<>(groups);
3256 }
3257
3258 private void verifyPrivilegedListener(INotificationListener token, UserHandle user) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003259 ManagedServiceInfo info;
3260 synchronized (mNotificationLock) {
3261 info = mListeners.checkServiceTokenLocked(token);
3262 }
Julia Reynoldsda781472017-04-12 09:41:16 -04003263 if (!hasCompanionDevice(info)) {
3264 throw new SecurityException(info + " does not have access");
3265 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003266 if (!info.enabledAndUserMatches(user.getIdentifier())) {
3267 throw new SecurityException(info + " does not have access");
3268 }
3269 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003270
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04003271 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
3272 int uid = 0;
3273 long identity = Binder.clearCallingIdentity();
3274 try {
3275 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
3276 } finally {
3277 Binder.restoreCallingIdentity(identity);
3278 }
3279 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04003280 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003281
3282 @Override
3283 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
3284 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
3285 throws RemoteException {
3286 new ShellCmd().exec(this, in, out, err, args, callback, resultReceiver);
3287 }
John Spurlock1fc476d2015-04-14 16:05:20 -04003288 };
John Spurlocka4294292014-03-24 18:02:32 -04003289
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003290 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
3291 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003292 return;
3293 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04003294 if (adjustment.getSignals() != null) {
3295 Bundle.setDefusable(adjustment.getSignals(), true);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003296 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003297 }
3298 }
3299
Julia Reynolds88860ce2017-06-01 16:55:49 -04003300 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003301 void addAutogroupKeyLocked(String key) {
3302 NotificationRecord r = mNotificationsByKey.get(key);
3303 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003304 return;
3305 }
Julia Reynolds51710712017-07-19 13:48:07 -04003306 if (r.sbn.getOverrideGroupKey() == null) {
3307 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
3308 EventLogTags.writeNotificationAutogrouped(key);
3309 mRankingHandler.requestSort();
3310 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003311 }
3312
Julia Reynolds88860ce2017-06-01 16:55:49 -04003313 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003314 void removeAutogroupKeyLocked(String key) {
3315 NotificationRecord r = mNotificationsByKey.get(key);
3316 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003317 return;
3318 }
Julia Reynolds51710712017-07-19 13:48:07 -04003319 if (r.sbn.getOverrideGroupKey() != null) {
3320 addAutoGroupAdjustment(r, null);
3321 EventLogTags.writeNotificationUnautogrouped(key);
3322 mRankingHandler.requestSort();
3323 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04003324 }
3325
3326 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
3327 Bundle signals = new Bundle();
3328 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
3329 Adjustment adjustment =
3330 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
3331 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003332 }
3333
3334 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04003335 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04003336 private void clearAutogroupSummaryLocked(int userId, String pkg) {
3337 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3338 if (summaries != null && summaries.containsKey(pkg)) {
3339 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003340 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04003341 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04003342 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04003343 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003344 }
3345 }
3346 }
3347
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04003348 @GuardedBy("mNotificationLock")
3349 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
3350 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
3351 return summaries != null && summaries.containsKey(sbn.getPackageName());
3352 }
3353
Julia Reynoldse46bb372016-03-17 11:05:58 -04003354 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04003355 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
3356 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003357 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003358 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
3359 if (notificationRecord == null) {
3360 // The notification could have been cancelled again already. A successive
3361 // adjustment will post a summary if needed.
3362 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04003363 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04003364 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
3365 userId = adjustedSbn.getUser().getIdentifier();
3366 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
3367 if (summaries == null) {
3368 summaries = new ArrayMap<>();
3369 }
3370 mAutobundledSummaries.put(userId, summaries);
3371 if (!summaries.containsKey(pkg)) {
3372 // Add summary
3373 final ApplicationInfo appInfo =
3374 adjustedSbn.getNotification().extras.getParcelable(
3375 Notification.EXTRA_BUILDER_APPLICATION_INFO);
3376 final Bundle extras = new Bundle();
3377 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003378 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04003379 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05003380 new Notification.Builder(getContext(), channelId)
3381 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04003382 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04003383 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04003384 .setGroup(GroupHelper.AUTOGROUP_KEY)
3385 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
3386 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
3387 .setColor(adjustedSbn.getNotification().color)
3388 .setLocalOnly(true)
3389 .build();
3390 summaryNotification.extras.putAll(extras);
3391 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
3392 if (appIntent != null) {
3393 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
3394 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
3395 }
3396 final StatusBarNotification summarySbn =
3397 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003398 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003399 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04003400 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
3401 adjustedSbn.getInitialPid(), summaryNotification,
3402 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
3403 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05003404 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003405 notificationRecord.getChannel());
Julia Reynolds8f488d32016-10-14 10:59:01 -04003406 summaries.put(pkg, summarySbn.getKey());
3407 }
3408 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003409 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04003410 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04003411 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04003412 }
3413 }
3414
John Spurlock32fe4c62014-10-02 12:16:02 -04003415 private String disableNotificationEffects(NotificationRecord record) {
3416 if (mDisableNotificationEffects) {
3417 return "booleanState";
3418 }
3419 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
3420 return "listenerHints";
3421 }
3422 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
3423 return "callState";
3424 }
3425 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04003426 };
3427
Kweku Adams887f09c2017-11-13 17:12:20 -08003428 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04003429 JSONObject dump = new JSONObject();
3430 try {
3431 dump.put("service", "Notification Manager");
Chris Wrenacf424a2016-03-15 12:48:55 -04003432 dump.put("bans", mRankingHelper.dumpBansJson(filter));
3433 dump.put("ranking", mRankingHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003434 dump.put("stats", mUsageStats.dumpJson(filter));
Julia Reynoldsd373d782017-03-03 13:32:57 -05003435 dump.put("channels", mRankingHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04003436 } catch (JSONException e) {
3437 e.printStackTrace();
3438 }
3439 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04003440 }
3441
Kweku Adams887f09c2017-11-13 17:12:20 -08003442 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003443 final ProtoOutputStream proto = new ProtoOutputStream(fd);
3444 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003445 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003446 for (int i = 0; i < N; i++) {
3447 final NotificationRecord nr = mNotificationList.get(i);
3448 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3449 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3450 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003451 }
3452 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003453 for (int i = 0; i < N; i++) {
3454 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3455 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3456 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3457 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003458 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003459 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
3460 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08003461 for (int i = 0; i < N; i++) {
3462 final NotificationRecord nr = snoozed.get(i);
3463 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3464 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
3465 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003466 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003467
Kweku Adams93304b62017-09-20 17:03:00 -07003468 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
3469 mZenModeHelper.dump(proto);
3470 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08003471 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07003472 }
3473 proto.end(zenLog);
3474
3475 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
3476 mListeners.dump(proto, filter);
3477 proto.end(listenersToken);
3478
3479 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
3480
3481 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
3482 long effectsToken = proto.start(
3483 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
3484
3485 proto.write(
3486 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
3487 final ArraySet<ManagedServiceInfo> listeners =
3488 mListenersDisablingEffects.valueAt(i);
3489 for (int j = 0; j < listeners.size(); j++) {
3490 final ManagedServiceInfo listener = listeners.valueAt(i);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08003491 listener.writeToProto(proto, ListenersDisablingEffectsProto.LISTENERS, null);
Kweku Adams93304b62017-09-20 17:03:00 -07003492 }
3493
3494 proto.end(effectsToken);
3495 }
3496
3497 long assistantsToken = proto.start(
3498 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
3499 mAssistants.dump(proto, filter);
3500 proto.end(assistantsToken);
3501
3502 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
3503 mConditionProviders.dump(proto, filter);
3504 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07003505
3506 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
3507 mRankingHelper.dump(proto, filter);
3508 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05003509 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003510
Julia Reynoldsc9842c12017-02-07 12:46:41 -05003511 proto.flush();
3512 }
3513
Kweku Adams887f09c2017-11-13 17:12:20 -08003514 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04003515 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04003516 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003517 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04003518 }
3519 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08003520 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003521 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08003522
John Spurlock50806fc2014-07-15 10:22:02 -04003523 if (!zenOnly) {
3524 synchronized (mToastQueue) {
3525 N = mToastQueue.size();
3526 if (N > 0) {
3527 pw.println(" Toast Queue:");
3528 for (int i=0; i<N; i++) {
3529 mToastQueue.get(i).dump(pw, " ", filter);
3530 }
3531 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003532 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003533 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003534 }
3535
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003536 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04003537 if (!zenOnly) {
3538 N = mNotificationList.size();
John Spurlock25e2d242014-06-27 13:58:23 -04003539 if (N > 0) {
John Spurlock50806fc2014-07-15 10:22:02 -04003540 pw.println(" Notification List:");
John Spurlock25e2d242014-06-27 13:58:23 -04003541 for (int i=0; i<N; i++) {
John Spurlock50806fc2014-07-15 10:22:02 -04003542 final NotificationRecord nr = mNotificationList.get(i);
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003543 if (filter.filtered && !filter.matches(nr.sbn)) continue;
Dan Sandlera1770312015-07-10 13:59:29 -04003544 nr.dump(pw, " ", getContext(), filter.redact);
John Spurlock25e2d242014-06-27 13:58:23 -04003545 }
3546 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08003547 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003548
Julia Reynoldse6b53e62015-07-31 09:25:10 -04003549 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04003550 N = mLights.size();
3551 if (N > 0) {
3552 pw.println(" Lights List:");
3553 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05003554 if (i == N - 1) {
3555 pw.print(" > ");
3556 } else {
3557 pw.print(" ");
3558 }
3559 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04003560 }
3561 pw.println(" ");
3562 }
John Spurlockcb566aa2014-08-03 22:58:28 -04003563 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
3564 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05003565 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
3566 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003567 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04003568 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04003569 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04003570 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04003571 }
3572 pw.println(" mArchive=" + mArchive.toString());
3573 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003574 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04003575 while (iter.hasNext()) {
3576 final StatusBarNotification sbn = iter.next();
3577 if (filter != null && !filter.matches(sbn)) continue;
3578 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003579 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04003580 if (iter.hasNext()) pw.println(" ...");
3581 break;
3582 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003583 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003584
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003585 if (!zenOnly) {
3586 N = mEnqueuedNotifications.size();
3587 if (N > 0) {
3588 pw.println(" Enqueued Notification List:");
3589 for (int i = 0; i < N; i++) {
3590 final NotificationRecord nr = mEnqueuedNotifications.get(i);
3591 if (filter.filtered && !filter.matches(nr.sbn)) continue;
3592 nr.dump(pw, " ", getContext(), filter.redact);
3593 }
3594 pw.println(" ");
3595 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003596
3597 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003598 }
3599 }
3600
John Spurlock50806fc2014-07-15 10:22:02 -04003601 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04003602 pw.println("\n Ranking Config:");
3603 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04003604
John Spurlock50806fc2014-07-15 10:22:02 -04003605 pw.println("\n Notification listeners:");
3606 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003607 pw.print(" mListenerHints: "); pw.println(mListenerHints);
3608 pw.print(" mListenersDisablingEffects: (");
3609 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04003610 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003611 final int hint = mListenersDisablingEffects.keyAt(i);
3612 if (i > 0) pw.print(';');
3613 pw.print("hint[" + hint + "]:");
3614
3615 final ArraySet<ManagedServiceInfo> listeners =
3616 mListenersDisablingEffects.valueAt(i);
3617 final int listenerSize = listeners.size();
3618
3619 for (int j = 0; j < listenerSize; j++) {
3620 if (i > 0) pw.print(',');
3621 final ManagedServiceInfo listener = listeners.valueAt(i);
3622 pw.print(listener.component);
3623 }
John Spurlock1fa865f2014-07-21 14:56:39 -04003624 }
3625 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05003626 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003627 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04003628 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003629
Julia Reynolds520df6e2017-02-13 09:05:10 -05003630 if (!filter.filtered || zenOnly) {
3631 pw.println("\n Zen Mode:");
3632 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
3633 mZenModeHelper.dump(pw, " ");
3634
3635 pw.println("\n Zen Log:");
3636 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003637 }
3638
John Spurlocke77bb362014-04-26 10:24:59 -04003639 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04003640 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02003641
3642 pw.println("\n Group summaries:");
3643 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
3644 NotificationRecord r = entry.getValue();
3645 pw.println(" " + entry.getKey() + " -> " + r.getKey());
3646 if (mNotificationsByKey.get(r.getKey()) != r) {
3647 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04003648 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02003649 }
3650 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05003651
3652 if (!zenOnly) {
3653 pw.println("\n Usage Stats:");
3654 mUsageStats.dump(pw, " ", filter);
3655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 }
3657 }
3658
Adam Lesinski182f73f2013-12-05 16:48:06 -08003659 /**
3660 * The private API only accessible to the system process.
3661 */
3662 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
3663 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04003664 public NotificationChannel getNotificationChannel(String pkg, int uid, String
3665 channelId) {
3666 return mRankingHelper.getNotificationChannel(pkg, uid, channelId, false);
3667 }
3668
3669 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003670 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003671 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003672 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003673 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003674 }
Christoph Studer365e4c32014-09-18 20:35:36 +02003675
3676 @Override
3677 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
3678 int userId) {
3679 checkCallerIsSystem();
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003680 mHandler.post(new Runnable() {
3681 @Override
3682 public void run() {
3683 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003684 removeForegroundServiceFlagByListLocked(
3685 mEnqueuedNotifications, pkg, notificationId, userId);
3686 removeForegroundServiceFlagByListLocked(
3687 mNotificationList, pkg, notificationId, userId);
Julia Reynolds8f488d32016-10-14 10:59:01 -04003688 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003689 }
3690 });
3691 }
3692
Julia Reynolds88860ce2017-06-01 16:55:49 -04003693 @GuardedBy("mNotificationLock")
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003694 private void removeForegroundServiceFlagByListLocked(
Julia Reynolds88860ce2017-06-01 16:55:49 -04003695 ArrayList<NotificationRecord> notificationList, String pkg, int notificationId,
3696 int userId) {
3697 NotificationRecord r = findNotificationByListLocked(
3698 notificationList, pkg, null, notificationId, userId);
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003699 if (r == null) {
3700 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02003701 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04003702 StatusBarNotification sbn = r.sbn;
3703 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
3704 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
3705 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
3706 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
3707 sbn.getNotification().flags =
3708 (r.mOriginalFlags & ~Notification.FLAG_FOREGROUND_SERVICE);
3709 mRankingHelper.sort(mNotificationList);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003710 mListeners.notifyPostedLocked(r, sbn /* oldSbn */);
Christoph Studer365e4c32014-09-18 20:35:36 +02003711 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003712 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04003714 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04003715 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04003716 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04003717 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08003718 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
3719 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04003720 }
John Spurlock7340fc82014-04-24 18:50:12 -04003721 checkCallerIsSystemOrSameApp(pkg);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08003722
Scott Greenwald9b05c612013-06-25 23:44:05 -04003723 final int userId = ActivityManager.handleIncomingUser(callingPid,
3724 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
Jeff Sharkey65c4a2b2012-09-25 17:22:27 -07003725 final UserHandle user = new UserHandle(userId);
Dianne Hackborn41203752012-08-31 14:05:51 -07003726
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003727 if (pkg == null || notification == null) {
3728 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
3729 + " id=" + id + " notification=" + notification);
3730 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003731
3732 // The system can post notifications for any package, let us resolve that.
3733 final int notificationUid = resolveNotificationUid(opPkg, callingUid, userId);
3734
Julia Reynoldse46bb372016-03-17 11:05:58 -04003735 // Fix the notification as best we can.
3736 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003737 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
Jeff Sharkey012bc7b2016-04-11 16:30:27 -06003738 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
Julia Reynoldse0d711f2017-09-01 08:50:47 -04003739 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
Julia Reynoldse071abd2017-03-22 10:52:11 -04003740 Notification.addFieldsFromContext(ai, notification);
Julia Reynolds4db59552017-06-30 13:34:01 -04003741
3742 int canColorize = mPackageManagerClient.checkPermission(
3743 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
3744 if (canColorize == PERMISSION_GRANTED) {
3745 notification.flags |= Notification.FLAG_CAN_COLORIZE;
3746 } else {
3747 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
3748 }
3749
Julia Reynoldse46bb372016-03-17 11:05:58 -04003750 } catch (NameNotFoundException e) {
3751 Slog.e(TAG, "Cannot create a context for sending app", e);
3752 return;
3753 }
3754
Chris Wren888b7a82016-06-17 15:47:19 -04003755 mUsageStats.registerEnqueuedByApp(pkg);
3756
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003757 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04003758 String channelId = notification.getChannelId();
3759 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
3760 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05003761 }
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003762 final NotificationChannel channel = mRankingHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003763 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003764 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003765 final String noChannelStr = "No Channel found for "
3766 + "pkg=" + pkg
3767 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04003768 + ", id=" + id
3769 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003770 + ", opPkg=" + opPkg
3771 + ", callingUid=" + callingUid
3772 + ", userId=" + userId
3773 + ", incomingUserId=" + incomingUserId
3774 + ", notificationUid=" + notificationUid
3775 + ", notification=" + notification;
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003776 Log.e(TAG, noChannelStr);
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003777 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
Geoffrey Pitschcadb5dc2017-04-11 11:35:02 -04003778 "Failed to post notification on channel \"" + channelId + "\"\n" +
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003779 "See log for more details");
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04003780 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05003781 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003782
Chris Wrena61f1792016-08-04 11:24:42 -04003783 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003784 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05003785 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00003786 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Chris Wrena61f1792016-08-04 11:24:42 -04003787
Julia Reynolds8617e4e2017-09-18 16:52:37 -04003788 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
3789 && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
3790 && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
3791 // Increase the importance of foreground service notifications unless the user had an
3792 // opinion otherwise
3793 if (TextUtils.isEmpty(channelId)
3794 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
3795 r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
3796 } else {
3797 channel.setImportance(IMPORTANCE_LOW);
3798 mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
3799 r.updateNotificationChannel(channel);
3800 }
3801 }
3802
Julia Reynolds5e702192017-08-18 09:22:40 -04003803 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
3804 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003805 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07003806 }
3807
Felipe Lemedd85da62016-06-28 11:29:54 -07003808 // Whitelist pending intents.
3809 if (notification.allPendingIntents != null) {
3810 final int intentCount = notification.allPendingIntents.size();
3811 if (intentCount > 0) {
3812 final ActivityManagerInternal am = LocalServices
3813 .getService(ActivityManagerInternal.class);
3814 final long duration = LocalServices.getService(
3815 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
3816 for (int i = 0; i < intentCount; i++) {
3817 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
3818 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07003819 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
3820 WHITELIST_TOKEN, duration);
Felipe Lemedd85da62016-06-28 11:29:54 -07003821 }
3822 }
3823 }
3824 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07003825
Chris Wren47633422016-01-22 09:56:59 -05003826 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 }
3828
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04003829 private void doChannelWarningToast(CharSequence toastText) {
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003830 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003831 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
Geoffrey Pitsch507822d2017-05-11 12:57:22 -04003832 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
3833 if (warningEnabled) {
Geoffrey Pitsch2486f892017-05-22 10:53:44 -04003834 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
Geoffrey Pitsch5bdddbd2017-05-26 10:50:05 -04003835 Toast.LENGTH_SHORT);
Geoffrey Pitschd34c1872017-05-04 16:02:15 -04003836 toast.show();
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04003837 }
3838 }
3839
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003840 private int resolveNotificationUid(String opPackageName, int callingUid, int userId) {
3841 // The system can post notifications on behalf of any package it wants
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003842 if (isCallerSystemOrPhone() && opPackageName != null && !"android".equals(opPackageName)) {
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08003843 try {
3844 return getContext().getPackageManager()
3845 .getPackageUidAsUser(opPackageName, userId);
3846 } catch (NameNotFoundException e) {
3847 /* ignore */
3848 }
3849 }
3850 return callingUid;
3851 }
3852
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003853 /**
3854 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
3855 *
3856 * Has side effects.
3857 */
3858 private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04003859 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003860 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003861 final boolean isSystemNotification =
3862 isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003863 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
3864
3865 // Limit the number of notifications that any given package except the android
3866 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
3867 if (!isSystemNotification && !isNotificationFromListener) {
3868 synchronized (mNotificationLock) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003869 if (mNotificationsByKey.get(r.sbn.getKey()) == null && isCallerInstantApp(pkg)) {
3870 // Ephemeral apps have some special constraints for notifications.
3871 // They are not allowed to create new notifications however they are allowed to
3872 // update notifications created by the system (e.g. a foreground service
3873 // notification).
3874 throw new SecurityException("Instant app " + pkg
3875 + " cannot create notifications");
3876 }
3877
3878 // rate limit updates that aren't completed progress notifications
3879 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04003880 && !r.getNotification().hasCompletedProgress()
3881 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003882
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003883 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
3884 if (appEnqueueRate > mMaxPackageEnqueueRate) {
3885 mUsageStats.registerOverRateQuota(pkg);
3886 final long now = SystemClock.elapsedRealtime();
3887 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
3888 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04003889 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003890 mLastOverRateLogTime = now;
3891 }
3892 return false;
3893 }
3894 }
3895
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003896 // limit the number of outstanding notificationrecords an app can have
3897 int count = getNotificationCountLocked(pkg, userId, id, tag);
3898 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
3899 mUsageStats.registerOverCountQuota(pkg);
3900 Slog.e(TAG, "Package has already posted or enqueued " + count
3901 + " notifications. Not showing more. package=" + pkg);
3902 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003903 }
3904 }
3905 }
3906
3907 // snoozed apps
3908 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05003909 MetricsLogger.action(r.getLogMaker()
3910 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
3911 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003912 if (DBG) {
3913 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
3914 }
3915 mSnoozeHelper.update(userId, r);
3916 savePolicyFile();
3917 return false;
3918 }
3919
3920
3921 // blocked apps
3922 if (isBlocked(r, mUsageStats)) {
3923 return false;
3924 }
3925
3926 return true;
3927 }
3928
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04003929 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
3930 String excludedTag) {
3931 int count = 0;
3932 final int N = mNotificationList.size();
3933 for (int i = 0; i < N; i++) {
3934 final NotificationRecord existing = mNotificationList.get(i);
3935 if (existing.sbn.getPackageName().equals(pkg)
3936 && existing.sbn.getUserId() == userId) {
3937 if (existing.sbn.getId() == excludedId
3938 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
3939 continue;
3940 }
3941 count++;
3942 }
3943 }
3944 final int M = mEnqueuedNotifications.size();
3945 for (int i = 0; i < M; i++) {
3946 final NotificationRecord existing = mEnqueuedNotifications.get(i);
3947 if (existing.sbn.getPackageName().equals(pkg)
3948 && existing.sbn.getUserId() == userId) {
3949 count++;
3950 }
3951 }
3952 return count;
3953 }
3954
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003955 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
3956 final String pkg = r.sbn.getPackageName();
3957 final int callingUid = r.sbn.getUid();
3958
3959 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
3960 if (isPackageSuspended) {
3961 Slog.e(TAG, "Suppressing notification from package due to package "
3962 + "suspended by administrator.");
3963 usageStats.registerSuspendedByAdmin(r);
3964 return isPackageSuspended;
3965 }
Julia Reynolds4da79702017-06-01 11:06:10 -04003966 final boolean isBlocked =
Julia Reynolds005c8b92017-08-24 10:35:53 -04003967 mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
3968 || mRankingHelper.getImportance(pkg, callingUid)
3969 == NotificationManager.IMPORTANCE_NONE
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04003970 || r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05003971 if (isBlocked) {
3972 Slog.e(TAG, "Suppressing notification from package by user request.");
3973 usageStats.registerBlocked(r);
3974 }
3975 return isBlocked;
3976 }
3977
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04003978 protected class SnoozeNotificationRunnable implements Runnable {
3979 private final String mKey;
3980 private final long mDuration;
3981 private final String mSnoozeCriterionId;
3982
3983 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
3984 mKey = key;
3985 mDuration = duration;
3986 mSnoozeCriterionId = snoozeCriterionId;
3987 }
3988
3989 @Override
3990 public void run() {
3991 synchronized (mNotificationLock) {
3992 final NotificationRecord r = findNotificationByKeyLocked(mKey);
3993 if (r != null) {
3994 snoozeLocked(r);
3995 }
3996 }
3997 }
3998
Julia Reynolds88860ce2017-06-01 16:55:49 -04003999 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004000 void snoozeLocked(NotificationRecord r) {
4001 if (r.sbn.isGroup()) {
4002 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
4003 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
4004 if (r.getNotification().isGroupSummary()) {
4005 // snooze summary and all children
4006 for (int i = 0; i < groupNotifications.size(); i++) {
4007 snoozeNotificationLocked(groupNotifications.get(i));
4008 }
4009 } else {
4010 // if there is a valid summary for this group, and we are snoozing the only
4011 // child, also snooze the summary
4012 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
4013 if (groupNotifications.size() != 2) {
4014 snoozeNotificationLocked(r);
4015 } else {
4016 // snooze summary and the one child
4017 for (int i = 0; i < groupNotifications.size(); i++) {
4018 snoozeNotificationLocked(groupNotifications.get(i));
4019 }
4020 }
4021 } else {
4022 snoozeNotificationLocked(r);
4023 }
4024 }
4025 } else {
4026 // just snooze the one notification
4027 snoozeNotificationLocked(r);
4028 }
4029 }
4030
Julia Reynolds88860ce2017-06-01 16:55:49 -04004031 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004032 void snoozeNotificationLocked(NotificationRecord r) {
4033 MetricsLogger.action(r.getLogMaker()
4034 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
4035 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04004036 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
4037 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004038 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
4039 mSnoozeCriterionId == null ? 0 : 1));
Julia Reynolds0839c022017-06-15 15:24:01 -04004040 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004041 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004042 updateLightsLocked();
4043 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004044 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004045 mSnoozeHelper.snooze(r);
4046 } else {
4047 mSnoozeHelper.snooze(r, mDuration);
4048 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004049 r.recordSnoozed();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004050 savePolicyFile();
4051 }
4052 }
4053
Julia Reynoldsbaff4002016-12-15 11:34:26 -05004054 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05004055 private final NotificationRecord r;
4056 private final int userId;
4057
4058 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
4059 this.userId = userId;
4060 this.r = r;
4061 };
4062
4063 @Override
4064 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004065 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05004066 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05004067 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05004068
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004069 final StatusBarNotification n = r.sbn;
4070 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
4071 NotificationRecord old = mNotificationsByKey.get(n.getKey());
4072 if (old != null) {
4073 // Retain ranking information from previous record
4074 r.copyRankingInformation(old);
4075 }
4076
4077 final int callingUid = n.getUid();
4078 final int callingPid = n.getInitialPid();
4079 final Notification notification = n.getNotification();
4080 final String pkg = n.getPackageName();
4081 final int id = n.getId();
4082 final String tag = n.getTag();
4083
4084 // Handle grouped notifications and bail out early if we
4085 // can to avoid extracting signals.
4086 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
4087
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04004088 // if this is a group child, unsnooze parent summary
4089 if (n.isGroup() && notification.isGroupChild()) {
4090 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
4091 }
4092
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004093 // This conditional is a dirty hack to limit the logging done on
4094 // behalf of the download manager without affecting other apps.
4095 if (!pkg.equals("com.android.providers.downloads")
4096 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
4097 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05004098 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004099 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05004100 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004101 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
4102 pkg, id, tag, userId, notification.toString(),
4103 enqueueStatus);
4104 }
Chris Wren6676dab2016-12-21 18:26:27 -05004105
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004106 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05004107
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004108 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004109 if (mAssistants.isEnabled()) {
4110 mAssistants.onNotificationEnqueued(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004111 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004112 DELAY_FOR_ASSISTANT_TIME);
4113 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004114 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004115 }
4116 }
4117 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004118 }
4119
4120 protected class PostNotificationRunnable implements Runnable {
4121 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004122
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004123 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004124 this.key = key;
4125 }
4126
4127 @Override
4128 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004129 synchronized (mNotificationLock) {
4130 try {
4131 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004132 int N = mEnqueuedNotifications.size();
4133 for (int i = 0; i < N; i++) {
4134 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4135 if (Objects.equals(key, enqueued.getKey())) {
4136 r = enqueued;
4137 break;
Chris Wren6676dab2016-12-21 18:26:27 -05004138 }
Chris Wren6676dab2016-12-21 18:26:27 -05004139 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004140 if (r == null) {
4141 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
4142 return;
4143 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004144 NotificationRecord old = mNotificationsByKey.get(key);
4145 final StatusBarNotification n = r.sbn;
4146 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05004147 int index = indexOfNotificationLocked(n.getKey());
4148 if (index < 0) {
4149 mNotificationList.add(r);
4150 mUsageStats.registerPostedByApp(r);
4151 } else {
4152 old = mNotificationList.get(index);
4153 mNotificationList.set(index, r);
4154 mUsageStats.registerUpdatedByApp(r, old);
4155 // Make sure we don't lose the foreground service state.
4156 notification.flags |=
4157 old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004158 // revoke uri permissions for changed uris
4159 revokeUriPermissions(r, old);
Chris Wren6676dab2016-12-21 18:26:27 -05004160 r.isUpdate = true;
4161 }
4162
4163 mNotificationsByKey.put(n.getKey(), r);
4164
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004165 if (!r.isUpdate) {
4166 logRecentLocked(r);
4167 }
4168
Chris Wren6676dab2016-12-21 18:26:27 -05004169 // Ensure if this is a foreground service that the proper additional
4170 // flags are set.
4171 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4172 notification.flags |= Notification.FLAG_ONGOING_EVENT
4173 | Notification.FLAG_NO_CLEAR;
4174 }
4175
4176 applyZenModeLocked(r);
4177 mRankingHelper.sort(mNotificationList);
4178
4179 if (notification.getSmallIcon() != null) {
4180 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004181 mListeners.notifyPostedLocked(r, oldSbn);
Julia Reynolds8aebf352017-06-26 11:35:33 -04004182 if (oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup())) {
4183 mHandler.post(new Runnable() {
4184 @Override
4185 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004186 mGroupHelper.onNotificationPosted(
4187 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04004188 }
4189 });
4190 }
Chris Wren6676dab2016-12-21 18:26:27 -05004191 } else {
4192 Slog.e(TAG, "Not posting notification without small icon: " + notification);
4193 if (old != null && !old.isCanceled) {
4194 mListeners.notifyRemovedLocked(n,
Julia Reynolds503ed942017-10-04 16:04:56 -04004195 NotificationListenerService.REASON_ERROR, null);
Chris Wren6676dab2016-12-21 18:26:27 -05004196 mHandler.post(new Runnable() {
4197 @Override
4198 public void run() {
4199 mGroupHelper.onNotificationRemoved(n);
4200 }
4201 });
4202 }
4203 // ATTENTION: in a future release we will bail out here
4204 // so that we do not play sounds, show lights, etc. for invalid
4205 // notifications
4206 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
4207 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05004208 }
Chris Wren47633422016-01-22 09:56:59 -05004209
Chris Wren6676dab2016-12-21 18:26:27 -05004210 buzzBeepBlinkLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004211 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004212 int N = mEnqueuedNotifications.size();
4213 for (int i = 0; i < N; i++) {
4214 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
4215 if (Objects.equals(key, enqueued.getKey())) {
4216 mEnqueuedNotifications.remove(i);
4217 break;
4218 }
4219 }
Chris Wren6676dab2016-12-21 18:26:27 -05004220 }
Chris Wren47633422016-01-22 09:56:59 -05004221 }
4222 }
4223 }
4224
Christoph Studer265c1052014-07-23 17:14:33 +02004225 /**
Julia Reynolds7bcb57b2018-01-22 10:37:58 -05004226 * Keeps the last 5 packages that have notified, by user.
4227 */
4228 @GuardedBy("mNotificationLock")
4229 @VisibleForTesting
4230 protected void logRecentLocked(NotificationRecord r) {
4231 if (r.isUpdate) {
4232 return;
4233 }
4234 ArrayList<NotifyingApp> recentAppsForUser =
4235 mRecentApps.getOrDefault(r.getUser().getIdentifier(), new ArrayList<>(6));
4236 NotifyingApp na = new NotifyingApp()
4237 .setPackage(r.sbn.getPackageName())
4238 .setUid(r.sbn.getUid())
4239 .setLastNotified(r.sbn.getPostTime());
4240 // A new notification gets an app moved to the front of the list
4241 for (int i = recentAppsForUser.size() - 1; i >= 0; i--) {
4242 NotifyingApp naExisting = recentAppsForUser.get(i);
4243 if (na.getPackage().equals(naExisting.getPackage())
4244 && na.getUid() == naExisting.getUid()) {
4245 recentAppsForUser.remove(i);
4246 break;
4247 }
4248 }
4249 // time is always increasing, so always add to the front of the list
4250 recentAppsForUser.add(0, na);
4251 if (recentAppsForUser.size() > 5) {
4252 recentAppsForUser.remove(recentAppsForUser.size() -1);
4253 }
4254 mRecentApps.put(r.getUser().getIdentifier(), recentAppsForUser);
4255 }
4256
4257 /**
Christoph Studer265c1052014-07-23 17:14:33 +02004258 * Ensures that grouped notification receive their special treatment.
4259 *
4260 * <p>Cancels group children if the new notification causes a group to lose
4261 * its summary.</p>
4262 *
4263 * <p>Updates mSummaryByGroupKey.</p>
4264 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004265 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02004266 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
4267 int callingUid, int callingPid) {
4268 StatusBarNotification sbn = r.sbn;
4269 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07004270 if (n.isGroupSummary() && !sbn.isAppGroup()) {
4271 // notifications without a group shouldn't be a summary, otherwise autobundling can
4272 // lead to bugs
4273 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
4274 }
4275
Christoph Studer265c1052014-07-23 17:14:33 +02004276 String group = sbn.getGroupKey();
4277 boolean isSummary = n.isGroupSummary();
4278
4279 Notification oldN = old != null ? old.sbn.getNotification() : null;
4280 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
4281 boolean oldIsSummary = old != null && oldN.isGroupSummary();
4282
4283 if (oldIsSummary) {
4284 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
4285 if (removedSummary != old) {
4286 String removedKey =
4287 removedSummary != null ? removedSummary.getKey() : "<null>";
4288 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
4289 ", removed=" + removedKey);
4290 }
4291 }
4292 if (isSummary) {
4293 mSummaryByGroupKey.put(group, r);
4294 }
4295
4296 // Clear out group children of the old notification if the update
4297 // causes the group summary to go away. This happens when the old
4298 // notification was a summary and the new one isn't, or when the old
4299 // notification was a summary and its group key changed.
4300 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04004301 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
4302 null);
Christoph Studer265c1052014-07-23 17:14:33 +02004303 }
4304 }
4305
Chris Wren93bb8b82016-03-29 14:35:05 -04004306 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004307 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05004308 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04004309 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05004310 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
4311 REQUEST_CODE_TIMEOUT,
4312 new Intent(ACTION_NOTIFICATION_TIMEOUT)
4313 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
4314 .appendPath(record.getKey()).build())
4315 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
4316 .putExtra(EXTRA_KEY, record.getKey()),
4317 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05004318 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04004319 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05004320 }
4321 }
4322
4323 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04004324 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04004325 void buzzBeepBlinkLocked(NotificationRecord record) {
Chris Wren82ba59d2015-06-05 11:23:44 -04004326 boolean buzz = false;
4327 boolean beep = false;
4328 boolean blink = false;
4329
Chris Wrena3446562014-06-03 18:11:47 -04004330 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04004331 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04004332
4333 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04004334 final boolean aboveThreshold =
4335 record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04004336
4337 // Remember if this notification already owns the notification channels.
4338 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
4339 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04004340 // These are set inside the conditional if the notification is allowed to make noise.
4341 boolean hasValidVibrate = false;
4342 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04004343 boolean sentAccessibilityEvent = false;
4344 // If the notification will appear in the status bar, it should send an accessibility
4345 // event
4346 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
4347 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4348 sentAccessibilityEvent = true;
4349 }
Chris Wrena3446562014-06-03 18:11:47 -04004350
Julia Reynolds76c096d2017-06-19 08:16:04 -04004351 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004352
Julia Reynolds76c096d2017-06-19 08:16:04 -04004353 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004354 Uri soundUri = record.getSound();
4355 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
4356 long[] vibration = record.getVibration();
4357 // Demote sound to vibration if vibration missing & phone in vibration mode.
4358 if (vibration == null
4359 && hasValidSound
4360 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04004361 == AudioManager.RINGER_MODE_VIBRATE)
4362 && mAudioManager.getStreamVolume(
4363 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04004364 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04004365 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04004366 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01004367
Julia Reynolds76c096d2017-06-19 08:16:04 -04004368 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04004369 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04004370 if (!sentAccessibilityEvent) {
4371 sendAccessibilityEvent(notification, record.sbn.getPackageName());
4372 sentAccessibilityEvent = true;
4373 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004374 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04004375 if (hasValidSound) {
4376 mSoundNotificationKey = key;
4377 if (mInCall) {
4378 playInCallNotification();
4379 beep = true;
4380 } else {
4381 beep = playSound(record, soundUri);
4382 }
4383 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004384
Julia Reynolds7c96b582017-05-25 12:35:36 -04004385 final boolean ringerModeSilent =
4386 mAudioManager.getRingerModeInternal()
4387 == AudioManager.RINGER_MODE_SILENT;
4388 if (!mInCall && hasValidVibrate && !ringerModeSilent) {
4389 mVibrateNotificationKey = key;
4390
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004391 buzz = playVibration(record, vibration, hasValidSound);
Julia Reynolds7c96b582017-05-25 12:35:36 -04004392 }
Chris Wrena3446562014-06-03 18:11:47 -04004393 }
4394 }
Chris Wren93bb8b82016-03-29 14:35:05 -04004395 }
4396 // If a notification is updated to remove the actively playing sound or vibrate,
4397 // cancel that feedback now
4398 if (wasBeep && !hasValidSound) {
4399 clearSoundLocked();
4400 }
4401 if (wasBuzz && !hasValidVibrate) {
4402 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04004403 }
4404
4405 // light
4406 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04004407 boolean wasShowLights = mLights.remove(key);
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05004408 if (record.getLight() != null && aboveThreshold
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004409 && ((record.getSuppressedVisualEffects()
Julia Reynoldsd5607292016-02-05 15:25:58 -05004410 & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_OFF) == 0)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04004411 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04004412 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04004413 if (mUseAttentionLight) {
4414 mAttentionLight.pulse();
4415 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004416 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04004417 } else if (wasShowLights) {
4418 updateLightsLocked();
4419 }
Chris Wren82ba59d2015-06-05 11:23:44 -04004420 if (buzz || beep || blink) {
Julia Reynolds445cfa82017-05-08 15:41:45 -04004421 MetricsLogger.action(record.getLogMaker()
4422 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
4423 .setType(MetricsEvent.TYPE_OPEN)
4424 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
4425 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04004426 }
Chris Wrena3446562014-06-03 18:11:47 -04004427 }
4428
Julia Reynolds88860ce2017-06-01 16:55:49 -04004429 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004430 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04004431 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004432 final Notification notification = record.getNotification();
4433 if(record.isUpdate
4434 && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
4435 return true;
4436 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004437
Julia Reynolds76c096d2017-06-19 08:16:04 -04004438 // muted by listener
4439 final String disableEffects = disableNotificationEffects(record);
4440 if (disableEffects != null) {
4441 ZenLog.traceDisableEffects(record, disableEffects);
4442 return true;
4443 }
4444
4445 // suppressed due to DND
4446 if (record.isIntercepted()) {
4447 return true;
4448 }
4449
4450 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004451 if (record.sbn.isGroup()) {
Julia Reynolds30203152017-05-26 13:36:31 -04004452 return notification.suppressAlertingDueToGrouping();
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004453 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04004454
Julia Reynolds65b85cf2017-07-20 09:19:20 -04004455 // Suppressed for being too recently noisy
4456 final String pkg = record.sbn.getPackageName();
4457 if (mUsageStats.isAlertRateLimited(pkg)) {
4458 Slog.e(TAG, "Muting recently noisy " + record.getKey());
4459 return true;
4460 }
4461
Julia Reynoldsa79c3712017-04-21 10:29:57 -04004462 return false;
4463 }
4464
Julia Reynolds0c299d42016-11-15 14:37:04 -05004465 private boolean playSound(final NotificationRecord record, Uri soundUri) {
4466 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4467 // do not play notifications if there is a user of exclusive audio focus
Julia Reynolds2143e5d2017-01-17 16:28:48 -05004468 // or the device is in vibrate mode
Julia Reynolds85896572017-09-20 12:54:52 -04004469 if (!mAudioManager.isAudioFocusExclusive() && (mAudioManager.getRingerModeInternal()
4470 != AudioManager.RINGER_MODE_VIBRATE || mAudioManager.getStreamVolume(
4471 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05004472 final long identity = Binder.clearCallingIdentity();
4473 try {
4474 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4475 if (player != null) {
4476 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
4477 + " with attributes " + record.getAudioAttributes());
4478 player.playAsync(soundUri, record.sbn.getUser(), looping,
4479 record.getAudioAttributes());
4480 return true;
4481 }
4482 } catch (RemoteException e) {
4483 } finally {
4484 Binder.restoreCallingIdentity(identity);
4485 }
4486 }
4487 return false;
4488 }
4489
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004490 private boolean playVibration(final NotificationRecord record, long[] vibration,
4491 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004492 // Escalate privileges so we can use the vibrator even if the
4493 // notifying app does not have the VIBRATE permission.
4494 long identity = Binder.clearCallingIdentity();
4495 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07004496 final VibrationEffect effect;
4497 try {
4498 final boolean insistent =
4499 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
4500 effect = VibrationEffect.createWaveform(
4501 vibration, insistent ? 0 : -1 /*repeatIndex*/);
4502 } catch (IllegalArgumentException e) {
4503 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
4504 Arrays.toString(vibration));
4505 return false;
4506 }
4507 if (delayVibForSound) {
4508 new Thread(() -> {
4509 // delay the vibration by the same amount as the notification sound
4510 final int waitMs = mAudioManager.getFocusRampTimeMs(
4511 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
4512 record.getAudioAttributes());
4513 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
4514 try {
4515 Thread.sleep(waitMs);
4516 } catch (InterruptedException e) { }
4517 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4518 effect, record.getAudioAttributes());
4519 }).start();
4520 } else {
4521 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
4522 effect, record.getAudioAttributes());
4523 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04004524 return true;
4525 } finally{
4526 Binder.restoreCallingIdentity(identity);
4527 }
4528 }
4529
Julia Reynolds7c96b582017-05-25 12:35:36 -04004530 private boolean isNotificationForCurrentUser(NotificationRecord record) {
4531 final int currentUser;
4532 final long token = Binder.clearCallingIdentity();
4533 try {
4534 currentUser = ActivityManager.getCurrentUser();
4535 } finally {
4536 Binder.restoreCallingIdentity(token);
4537 }
4538 return (record.getUserId() == UserHandle.USER_ALL ||
4539 record.getUserId() == currentUser ||
4540 mUserProfiles.isCurrentProfile(record.getUserId()));
4541 }
4542
Beverly5d463b62017-07-26 14:13:40 -04004543 protected void playInCallNotification() {
Marta Białka39c992f2011-03-10 10:27:24 +01004544 new Thread() {
4545 @Override
4546 public void run() {
Beverly5d463b62017-07-26 14:13:40 -04004547 final long identity = Binder.clearCallingIdentity();
Marta Białka39c992f2011-03-10 10:27:24 +01004548 try {
Beverly5d463b62017-07-26 14:13:40 -04004549 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4550 if (player != null) {
4551 player.play(new Binder(), mInCallNotificationUri,
4552 mInCallNotificationAudioAttributes,
4553 mInCallNotificationVolume, false);
Marta Białka39c992f2011-03-10 10:27:24 +01004554 }
Beverly5d463b62017-07-26 14:13:40 -04004555 } catch (RemoteException e) {
4556 } finally {
4557 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01004558 }
4559 }
4560 }.start();
4561 }
4562
Julia Reynolds88860ce2017-06-01 16:55:49 -04004563 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004564 void showNextToastLocked() {
4565 ToastRecord record = mToastQueue.get(0);
4566 while (record != null) {
4567 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
4568 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004569 record.callback.show(record.token);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004570 scheduleTimeoutLocked(record);
4571 return;
4572 } catch (RemoteException e) {
4573 Slog.w(TAG, "Object died trying to show notification " + record.callback
4574 + " in package " + record.pkg);
4575 // remove it from the list and let the process die
4576 int index = mToastQueue.indexOf(record);
4577 if (index >= 0) {
4578 mToastQueue.remove(index);
4579 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004580 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004581 if (mToastQueue.size() > 0) {
4582 record = mToastQueue.get(0);
4583 } else {
4584 record = null;
4585 }
4586 }
4587 }
4588 }
4589
Julia Reynolds88860ce2017-06-01 16:55:49 -04004590 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004591 void cancelToastLocked(int index) {
4592 ToastRecord record = mToastQueue.get(index);
4593 try {
4594 record.callback.hide();
4595 } catch (RemoteException e) {
4596 Slog.w(TAG, "Object died trying to hide notification " + record.callback
4597 + " in package " + record.pkg);
4598 // don't worry about this, we're about to remove it from
4599 // the list anyway
4600 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004601
4602 ToastRecord lastToast = mToastQueue.remove(index);
Wale Ogunwaleac2561e2016-11-01 15:43:46 -07004603 mWindowManagerInternal.removeWindowToken(lastToast.token, true, DEFAULT_DISPLAY);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004604
4605 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004606 if (mToastQueue.size() > 0) {
4607 // Show the next one. If the callback fails, this will remove
4608 // it from the list, so don't assume that the list hasn't changed
4609 // after this point.
4610 showNextToastLocked();
4611 }
4612 }
4613
Julia Reynolds88860ce2017-06-01 16:55:49 -04004614 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004615 private void scheduleTimeoutLocked(ToastRecord r)
4616 {
4617 mHandler.removeCallbacksAndMessages(r);
4618 Message m = Message.obtain(mHandler, MESSAGE_TIMEOUT, r);
4619 long delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
4620 mHandler.sendMessageDelayed(m, delay);
4621 }
4622
4623 private void handleTimeout(ToastRecord record)
4624 {
4625 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
4626 synchronized (mToastQueue) {
4627 int index = indexOfToastLocked(record.pkg, record.callback);
4628 if (index >= 0) {
4629 cancelToastLocked(index);
4630 }
4631 }
4632 }
4633
Julia Reynolds88860ce2017-06-01 16:55:49 -04004634 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08004635 int indexOfToastLocked(String pkg, ITransientNotification callback)
4636 {
4637 IBinder cbak = callback.asBinder();
4638 ArrayList<ToastRecord> list = mToastQueue;
4639 int len = list.size();
4640 for (int i=0; i<len; i++) {
4641 ToastRecord r = list.get(i);
Beverly4ee785b2017-08-11 12:49:56 -04004642 if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
4643 return i;
4644 }
4645 }
4646 return -1;
4647 }
4648
4649 @GuardedBy("mToastQueue")
4650 int indexOfToastPackageLocked(String pkg)
4651 {
4652 ArrayList<ToastRecord> list = mToastQueue;
4653 int len = list.size();
4654 for (int i=0; i<len; i++) {
4655 ToastRecord r = list.get(i);
4656 if (r.pkg.equals(pkg)) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004657 return i;
4658 }
4659 }
4660 return -1;
4661 }
4662
Julia Reynolds88860ce2017-06-01 16:55:49 -04004663 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07004664 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08004665 {
4666 int toastCount = 0; // toasts from this pid
4667 ArrayList<ToastRecord> list = mToastQueue;
4668 int N = list.size();
4669 for (int i=0; i<N; i++) {
4670 ToastRecord r = list.get(i);
4671 if (r.pid == pid) {
4672 toastCount++;
4673 }
4674 }
4675 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07004676 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08004677 } catch (RemoteException e) {
4678 // Shouldn't happen.
4679 }
4680 }
4681
Chris Wrenf9536642014-04-17 10:01:54 -04004682 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004683 if (!(message.obj instanceof RankingReconsideration)) return;
4684 RankingReconsideration recon = (RankingReconsideration) message.obj;
4685 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04004686 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004687 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04004688 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
4689 if (record == null) {
4690 return;
Chris Wrenf9536642014-04-17 10:01:54 -04004691 }
Chris Wren333a61c2014-05-28 16:40:57 -04004692 int indexBefore = findNotificationRecordIndexLocked(record);
4693 boolean interceptBefore = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004694 float contactAffinityBefore = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004695 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04004696 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04004697 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04004698 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04004699 int indexAfter = findNotificationRecordIndexLocked(record);
4700 boolean interceptAfter = record.isIntercepted();
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004701 float contactAffinityAfter = record.getContactAffinity();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004702 int visibilityAfter = record.getPackageVisibilityOverride();
4703 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
4704 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04004705 if (interceptBefore && !interceptAfter
4706 && Float.compare(contactAffinityBefore, contactAffinityAfter) != 0) {
Chris Wrena3446562014-06-03 18:11:47 -04004707 buzzBeepBlinkLocked(record);
4708 }
Chris Wrenf9536642014-04-17 10:01:54 -04004709 }
Chris Wren333a61c2014-05-28 16:40:57 -04004710 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004711 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04004712 }
4713 }
4714
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004715 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04004716 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004717 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04004718 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004719 // Any field that can change via one of the extractors needs to be added here.
4720 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004721 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05004722 boolean[] showBadges = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004723 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
4724 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
4725 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
4726 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04004727 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Chris Wren54bbef42014-07-09 18:37:56 -04004728 for (int i = 0; i < N; i++) {
4729 final NotificationRecord r = mNotificationList.get(i);
4730 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004731 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05004732 showBadges[i] = r.canShowBadge();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004733 channelBefore.add(r.getChannel());
4734 groupKeyBefore.add(r.getGroupKey());
4735 overridePeopleBefore.add(r.getPeopleOverride());
4736 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04004737 userSentimentBefore.add(r.getUserSentiment());
Chris Wren54bbef42014-07-09 18:37:56 -04004738 mRankingHelper.extractSignals(r);
4739 }
Chris Wren19a02b02015-12-22 10:34:22 -05004740 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04004741 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04004742 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004743 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05004744 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004745 || showBadges[i] != r.canShowBadge()
4746 || !Objects.equals(channelBefore.get(i), r.getChannel())
4747 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
4748 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04004749 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
4750 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004751 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04004752 return;
4753 }
4754 }
4755 }
4756 }
4757
Julia Reynolds88860ce2017-06-01 16:55:49 -04004758 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004759 private void recordCallerLocked(NotificationRecord record) {
4760 if (mZenModeHelper.isCall(record)) {
4761 mZenModeHelper.recordCaller(record);
4762 }
4763 }
4764
Christoph Studerd5092bc2014-07-03 17:47:58 +02004765 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04004766 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04004767 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02004768 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004769 if (record.isIntercepted()) {
Julia Reynoldsd5607292016-02-05 15:25:58 -05004770 int suppressed = (mZenModeHelper.shouldSuppressWhenScreenOff()
4771 ? SUPPRESSED_EFFECT_SCREEN_OFF : 0)
4772 | (mZenModeHelper.shouldSuppressWhenScreenOn()
4773 ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004774 record.setSuppressedVisualEffects(suppressed);
Julia Reynolds445cfa82017-05-08 15:41:45 -04004775 } else {
4776 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05004777 }
Chris Wren333a61c2014-05-28 16:40:57 -04004778 }
4779
Julia Reynolds88860ce2017-06-01 16:55:49 -04004780 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04004781 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04004782 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04004783 }
4784
Chris Wrenf9536642014-04-17 10:01:54 -04004785 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004786 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04004787 mListeners.notifyRankingUpdateLocked();
Chris Wrenf9536642014-04-17 10:01:54 -04004788 }
4789 }
4790
John Spurlockd8afe3c2014-08-01 14:04:07 -04004791 private void scheduleListenerHintsChanged(int state) {
4792 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
4793 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04004794 }
4795
Christoph Studer85a384b2014-08-27 20:16:15 +02004796 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
4797 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
4798 mHandler.obtainMessage(
4799 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
4800 listenerInterruptionFilter,
4801 0).sendToTarget();
4802 }
4803
John Spurlockd8afe3c2014-08-01 14:04:07 -04004804 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004805 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04004806 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04004807 }
4808 }
4809
Christoph Studer85a384b2014-08-27 20:16:15 +02004810 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004811 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02004812 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
4813 }
4814 }
4815
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004816 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08004817 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004818 public WorkerHandler(Looper looper) {
4819 super(looper);
4820 }
4821
Adam Lesinski182f73f2013-12-05 16:48:06 -08004822 @Override
4823 public void handleMessage(Message msg)
4824 {
4825 switch (msg.what)
4826 {
4827 case MESSAGE_TIMEOUT:
4828 handleTimeout((ToastRecord)msg.obj);
4829 break;
John Spurlock056c5192014-04-20 21:52:01 -04004830 case MESSAGE_SAVE_POLICY_FILE:
4831 handleSavePolicyFile();
4832 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004833 case MESSAGE_SEND_RANKING_UPDATE:
4834 handleSendRankingUpdate();
4835 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04004836 case MESSAGE_LISTENER_HINTS_CHANGED:
4837 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04004838 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02004839 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
4840 handleListenerInterruptionFilterChanged(msg.arg1);
4841 break;
Chris Wrenf9536642014-04-17 10:01:54 -04004842 }
4843 }
4844
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004845 protected void scheduleSendRankingUpdate() {
4846 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
4847 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
4848 sendMessage(m);
4849 }
4850 }
4851
Chris Wrenf9536642014-04-17 10:01:54 -04004852 }
4853
Chris Wren51017d02015-12-15 15:34:46 -05004854 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04004855 {
Chris Wren51017d02015-12-15 15:34:46 -05004856 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04004857 super(looper);
4858 }
4859
4860 @Override
4861 public void handleMessage(Message msg) {
4862 switch (msg.what) {
4863 case MESSAGE_RECONSIDER_RANKING:
4864 handleRankingReconsideration(msg);
4865 break;
Chris Wren51017d02015-12-15 15:34:46 -05004866 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004867 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04004868 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08004869 }
4870 }
Chris Wren51017d02015-12-15 15:34:46 -05004871
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004872 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05004873 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05004874 Message msg = Message.obtain();
4875 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05004876 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05004877 }
4878
4879 public void requestReconsideration(RankingReconsideration recon) {
4880 Message m = Message.obtain(this,
4881 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
4882 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
4883 sendMessageDelayed(m, delay);
4884 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004885 }
4886
Adam Lesinski182f73f2013-12-05 16:48:06 -08004887 // Notifications
4888 // ============================================================================
4889 static int clamp(int x, int low, int high) {
4890 return (x < low) ? low : ((x > high) ? high : x);
4891 }
4892
4893 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00004894 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07004895 return;
4896 }
4897
4898 AccessibilityEvent event =
4899 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
4900 event.setPackageName(packageName);
4901 event.setClassName(Notification.class.getName());
4902 event.setParcelableData(notification);
4903 CharSequence tickerText = notification.tickerText;
4904 if (!TextUtils.isEmpty(tickerText)) {
4905 event.getText().add(tickerText);
4906 }
4907
Julia Reynolds94187562017-10-10 13:58:49 -04004908 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07004909 }
4910
Julia Reynolds0839c022017-06-15 15:24:01 -04004911 /**
4912 * Removes all NotificationsRecords with the same key as the given notification record
4913 * from both lists. Do not call this method while iterating over either list.
4914 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04004915 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04004916 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
4917 // Remove from both lists, either list could have a separate Record for what is
4918 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004919 boolean wasPosted = false;
4920 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04004921 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
4922 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004923 mNotificationList.remove(recordInList);
4924 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004925 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004926 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04004927 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05004928 != null) {
4929 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004930 }
Julia Reynolds0839c022017-06-15 15:24:01 -04004931 return wasPosted;
4932 }
4933
4934 @GuardedBy("mNotificationLock")
4935 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04004936 boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04004937 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04004938
4939 // Record caller.
4940 recordCallerLocked(r);
4941
Julia Reynolds503ed942017-10-04 16:04:56 -04004942 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
4943 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
4944 }
4945
Julia Reynoldse0d711f2017-09-01 08:50:47 -04004946 // Revoke permissions
4947 revokeUriPermissions(null, r);
4948
Joe Onorato46439ce2010-11-19 13:56:21 -08004949 // tell the app
4950 if (sendDelete) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004951 if (r.getNotification().deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08004952 try {
Daniel Sandlerfde19b12013-01-17 00:21:05 -05004953 r.getNotification().deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08004954 } catch (PendingIntent.CanceledException ex) {
4955 // do nothing - there's no relevant way to recover, and
4956 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04004957 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08004958 }
4959 }
4960 }
4961
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004962 // Only cancel these if this notification actually got to be posted.
4963 if (wasPosted) {
4964 // status bar
4965 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05004966 if (reason != REASON_SNOOZED) {
4967 r.isCanceled = true;
4968 }
Julia Reynolds503ed942017-10-04 16:04:56 -04004969 mListeners.notifyRemovedLocked(r.sbn, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004970 mHandler.post(new Runnable() {
4971 @Override
4972 public void run() {
4973 mGroupHelper.onNotificationRemoved(r.sbn);
4974 }
4975 });
4976 }
4977
4978 // sound
4979 if (canceledKey.equals(mSoundNotificationKey)) {
4980 mSoundNotificationKey = null;
4981 final long identity = Binder.clearCallingIdentity();
4982 try {
4983 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
4984 if (player != null) {
4985 player.stopAsync();
4986 }
4987 } catch (RemoteException e) {
4988 } finally {
4989 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004990 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004992
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004993 // vibrate
4994 if (canceledKey.equals(mVibrateNotificationKey)) {
4995 mVibrateNotificationKey = null;
4996 long identity = Binder.clearCallingIdentity();
4997 try {
4998 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07004999 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005000 finally {
5001 Binder.restoreCallingIdentity(identity);
5002 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005004
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005005 // light
5006 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005007 }
5008
Christoph Studer546bec82014-03-14 12:17:12 +01005009 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04005010 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01005011 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005012 case REASON_CANCEL:
5013 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005014 case REASON_LISTENER_CANCEL:
5015 case REASON_LISTENER_CANCEL_ALL:
5016 mUsageStats.registerDismissedByUser(r);
5017 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05005018 case REASON_APP_CANCEL:
5019 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01005020 mUsageStats.registerRemovedByApp(r);
5021 break;
Christoph Studer546bec82014-03-14 12:17:12 +01005022 }
5023
Christoph Studer265c1052014-07-23 17:14:33 +02005024 String groupKey = r.getGroupKey();
5025 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005026 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02005027 mSummaryByGroupKey.remove(groupKey);
5028 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04005029 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
5030 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
5031 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04005032 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005033
Daniel Sandler23d7c702013-03-07 16:32:06 -05005034 // Save it for users of getHistoricalNotifications()
5035 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02005036
Chris Wren6650e572015-05-15 17:19:25 -04005037 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -05005038 MetricsLogger.action(r.getLogMaker(now)
5039 .setCategory(MetricsEvent.NOTIFICATION_ITEM)
5040 .setType(MetricsEvent.TYPE_DISMISS)
5041 .setSubtype(reason));
Chris Wrene6ddb8a2015-05-27 15:21:00 -04005042 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04005043 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now), listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005044 }
5045
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005046 void revokeUriPermissions(NotificationRecord newRecord, NotificationRecord oldRecord) {
5047 Set<Uri> oldUris = oldRecord.getNotificationUris();
5048 Set<Uri> newUris = newRecord == null ? new HashSet<>() : newRecord.getNotificationUris();
5049 oldUris.removeAll(newUris);
5050
5051 long ident = Binder.clearCallingIdentity();
5052 try {
5053 for (Uri uri : oldUris) {
5054 if (uri != null) {
5055 int notiUserId = oldRecord.getUserId();
5056 int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
5057 : ContentProvider.getUserIdFromUri(uri, notiUserId);
5058 uri = ContentProvider.getUriWithoutUserId(uri);
5059 mAm.revokeUriPermissionFromOwner(mPermissionOwner,
5060 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId);
5061 }
5062 }
5063 } catch (RemoteException e) {
5064 Log.e(TAG, "Count not revoke uri permissions", e);
5065 } finally {
5066 Binder.restoreCallingIdentity(ident);
5067 }
5068 }
5069
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005070 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07005071 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005072 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005073 */
John Spurlocke6a7d932014-03-13 12:29:00 -04005074 void cancelNotification(final int callingUid, final int callingPid,
5075 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005076 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04005077 final int userId, final int reason, final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005078 // In enqueueNotificationInternal notifications are added by scheduling the
5079 // work on the worker handler. Hence, we also schedule the cancel on this
5080 // handler to avoid a scenario where an add notification call followed by a
5081 // remove notification call ends up in not removing the notification.
5082 mHandler.post(new Runnable() {
5083 @Override
5084 public void run() {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005085 String listenerName = listener == null ? null : listener.component.toShortString();
Chris Wrenbddb5bc2015-03-04 08:47:46 -08005086 if (DBG) EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, id, tag,
5087 userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005088
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005089 synchronized (mNotificationLock) {
5090 // Look for the notification, searching both the posted and enqueued lists.
5091 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
5092 if (r != null) {
5093 // The notification was found, check if it should be removed.
Doug Zongkerab5c49c2009-12-04 10:31:43 -08005094
Christoph Studer546bec82014-03-14 12:17:12 +01005095 // Ideally we'd do this in the caller of this method. However, that would
5096 // require the caller to also find the notification.
Julia Reynoldsf619bc52017-03-17 08:32:23 -04005097 if (reason == REASON_CLICK) {
Christoph Studer546bec82014-03-14 12:17:12 +01005098 mUsageStats.registerClickedByUser(r);
5099 }
5100
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005101 if ((r.getNotification().flags & mustHaveFlags) != mustHaveFlags) {
5102 return;
5103 }
5104 if ((r.getNotification().flags & mustNotHaveFlags) != 0) {
5105 return;
5106 }
5107
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005108 // Cancel the notification.
Julia Reynolds0839c022017-06-15 15:24:01 -04005109 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005110 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Christoph Studer265c1052014-07-23 17:14:33 +02005111 cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005112 sendDelete, null);
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005113 updateLightsLocked();
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005114 } else {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005115 // No notification was found, assume that it is snoozed and cancel it.
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005116 if (reason != REASON_SNOOZED) {
5117 final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
5118 if (wasSnoozed) {
5119 savePolicyFile();
5120 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04005121 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005122 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005123 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005124 }
Svetoslav Ganov835835e2013-08-04 20:17:52 -07005125 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005126 }
5127
5128 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07005129 * Determine whether the userId applies to the notification in question, either because
5130 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
5131 */
5132 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
5133 return
5134 // looking for USER_ALL notifications? match everything
5135 userId == UserHandle.USER_ALL
5136 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005137 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07005138 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05005139 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07005140 }
5141
5142 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005143 * Determine whether the userId applies to the notification in question, either because
5144 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01005145 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005146 */
Kenny Guy2a764942014-04-02 13:29:20 +01005147 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00005148 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04005149 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005150 }
5151
5152 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05005153 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005154 * {@code mustHaveFlags}.
5155 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005156 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005157 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005158 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005159 mHandler.post(new Runnable() {
5160 @Override
5161 public void run() {
5162 String listenerName = listener == null ? null : listener.component.toShortString();
5163 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5164 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
5165 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005166
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005167 // Why does this parameter exist? Do we actually want to execute the above if doit
5168 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005169 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005170 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005171 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005172
5173 synchronized (mNotificationLock) {
5174 FlagChecker flagChecker = (int flags) -> {
5175 if ((flags & mustHaveFlags) != mustHaveFlags) {
5176 return false;
5177 }
5178 if ((flags & mustNotHaveFlags) != 0) {
5179 return false;
5180 }
5181 return true;
5182 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005183 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5184 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
5185 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005186 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005187 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5188 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
5189 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005190 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005191 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005192 }
5193 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005194 });
5195 }
5196
5197 private interface FlagChecker {
5198 // Returns false if these flags do not pass the defined flag test.
5199 public boolean apply(int flags);
5200 }
5201
Julia Reynolds88860ce2017-06-01 16:55:49 -04005202 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005203 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
5204 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
5205 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04005206 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005207 ArrayList<NotificationRecord> canceledNotifications = null;
5208 for (int i = notificationList.size() - 1; i >= 0; --i) {
5209 NotificationRecord r = notificationList.get(i);
5210 if (includeCurrentProfiles) {
5211 if (!notificationMatchesCurrentProfiles(r, userId)) {
5212 continue;
5213 }
5214 } else if (!notificationMatchesUserId(r, userId)) {
5215 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005216 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005217 // Don't remove notifications to all, if there's no package name specified
5218 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
5219 continue;
5220 }
5221 if (!flagChecker.apply(r.getFlags())) {
5222 continue;
5223 }
5224 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
5225 continue;
5226 }
5227 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
5228 continue;
5229 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005230 if (canceledNotifications == null) {
5231 canceledNotifications = new ArrayList<>();
5232 }
Julia Reynolds0839c022017-06-15 15:24:01 -04005233 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005234 mNotificationsByKey.remove(r.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005235 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005236 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005237 }
5238 if (canceledNotifications != null) {
5239 final int M = canceledNotifications.size();
5240 for (int i = 0; i < M; i++) {
5241 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005242 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005243 }
5244 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005245 }
5246 }
5247
Julia Reynolds50989772017-02-23 14:32:16 -05005248 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005249 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05005250 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05005251 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05005252 return;
5253 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05005254
Julia Reynolds79672302017-01-12 08:30:16 -05005255 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05005256 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
5257 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05005258 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005259 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005260 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005261 }
5262
5263 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
5264 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005265 if (DBG) {
5266 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
5267 }
Julia Reynolds79672302017-01-12 08:30:16 -05005268 mSnoozeHelper.repost(key);
5269 savePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05005270 }
5271
Julia Reynolds88860ce2017-06-01 16:55:49 -04005272 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07005273 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04005274 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005275 mHandler.post(new Runnable() {
5276 @Override
5277 public void run() {
5278 synchronized (mNotificationLock) {
5279 String listenerName =
5280 listener == null ? null : listener.component.toShortString();
5281 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
5282 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01005283
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005284 FlagChecker flagChecker = (int flags) -> {
5285 if ((flags & (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR))
5286 != 0) {
5287 return false;
5288 }
5289 return true;
5290 };
5291
5292 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
5293 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
5294 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04005295 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005296 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
5297 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
5298 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04005299 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005300 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00005301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005302 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005303 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005304 }
5305
Christoph Studere4ef156b2014-07-04 18:41:57 +02005306 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04005307 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02005308 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005309 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005310 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02005311 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02005312 return;
5313 }
5314
5315 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02005316
5317 if (pkg == null) {
5318 if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
5319 return;
5320 }
5321
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005322 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04005323 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005324 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04005325 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005326 }
5327
Julia Reynolds88860ce2017-06-01 16:55:49 -04005328 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005329 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
5330 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04005331 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005332 final String pkg = parentNotification.sbn.getPackageName();
5333 final int userId = parentNotification.getUserId();
5334 final int reason = REASON_GROUP_SUMMARY_CANCELED;
5335 for (int i = notificationList.size() - 1; i >= 0; i--) {
5336 final NotificationRecord childR = notificationList.get(i);
5337 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04005338 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005339 childR.getGroupKey().equals(parentNotification.getGroupKey())
Beverly40239d92017-07-07 10:20:41 -04005340 && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0
5341 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02005342 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
5343 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04005344 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04005345 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04005346 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02005347 }
5348 }
5349 }
5350
Julia Reynolds88860ce2017-06-01 16:55:49 -04005351 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005352 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005353 {
The Android Open Source Project10592532009-03-18 17:39:46 -07005354 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05005355 NotificationRecord ledNotification = null;
5356 while (ledNotification == null && !mLights.isEmpty()) {
5357 final String owner = mLights.get(mLights.size() - 1);
5358 ledNotification = mNotificationsByKey.get(owner);
5359 if (ledNotification == null) {
5360 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
5361 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005362 }
5363 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005364
Mike Lockwood63b5ad92011-08-30 09:55:30 -04005365 // Don't flash while we are in a call or screen is on
Chris Wren6054e612014-11-25 17:16:46 -05005366 if (ledNotification == null || mInCall || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05005367 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07005368 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005369 NotificationRecord.Light light = ledNotification.getLight();
5370 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05005371 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05005372 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
5373 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05005374 }
The Android Open Source Project10592532009-03-18 17:39:46 -07005375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005376 }
5377
Julia Reynolds88860ce2017-06-01 16:55:49 -04005378 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005379 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
5380 String groupKey, int userId) {
5381 List<NotificationRecord> records = new ArrayList<>();
5382 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
5383 records.addAll(
5384 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
5385 return records;
5386 }
5387
5388
Julia Reynolds88860ce2017-06-01 16:55:49 -04005389 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005390 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
5391 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
5392 List<NotificationRecord> records = new ArrayList<>();
5393 final int len = list.size();
5394 for (int i = 0; i < len; i++) {
5395 NotificationRecord r = list.get(i);
5396 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
5397 && r.sbn.getPackageName().equals(pkg)) {
5398 records.add(r);
5399 }
5400 }
5401 return records;
5402 }
5403
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005404 // Searches both enqueued and posted notifications by key.
5405 // TODO: need to combine a bunch of these getters with slightly different behavior.
5406 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04005407 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005408 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005409 NotificationRecord r;
5410 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
5411 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005412 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005413 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
5414 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005415 }
5416 return null;
5417 }
5418
Julia Reynolds88860ce2017-06-01 16:55:49 -04005419 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005420 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005421 NotificationRecord r;
5422 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
5423 return r;
5424 }
5425 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
5426 != null) {
5427 return r;
5428 }
5429 return null;
5430 }
5431
Julia Reynolds88860ce2017-06-01 16:55:49 -04005432 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005433 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005434 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005435 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005436 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005437 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01005438 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
5439 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005440 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005441 }
5442 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005443 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005444 }
5445
Julia Reynolds88860ce2017-06-01 16:55:49 -04005446 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005447 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04005448 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05005449 final int N = list.size();
5450 for (int i = 0; i < N; i++) {
5451 if (key.equals(list.get(i).getKey())) {
5452 return list.get(i);
5453 }
5454 }
5455 return null;
5456 }
5457
Julia Reynolds88860ce2017-06-01 16:55:49 -04005458 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02005459 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02005460 final int N = mNotificationList.size();
5461 for (int i = 0; i < N; i++) {
5462 if (key.equals(mNotificationList.get(i).getKey())) {
5463 return i;
5464 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02005465 }
Christoph Studerc5115552014-06-12 20:22:31 +02005466 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02005467 }
5468
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005469 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005470 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05005471 updateLightsLocked();
5472 }
5473 }
John Spurlocke677d712014-02-13 12:52:19 -05005474
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005475 protected boolean isCallingUidSystem() {
5476 final int uid = Binder.getCallingUid();
5477 return uid == Process.SYSTEM_UID;
5478 }
5479
5480 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04005481 final int appid = UserHandle.getAppId(uid);
5482 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
5483 }
John Spurlockb408e8e2014-04-23 21:12:45 -04005484
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005485 // TODO: Most calls should probably move to isCallerSystem.
5486 protected boolean isCallerSystemOrPhone() {
5487 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04005488 }
5489
Julia Reynoldsb852e562017-06-06 16:14:18 -04005490 private void checkCallerIsSystemOrShell() {
5491 if (Binder.getCallingUid() == Process.SHELL_UID) {
5492 return;
5493 }
5494 checkCallerIsSystem();
5495 }
5496
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005497 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005498 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005499 return;
5500 }
5501 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
5502 }
5503
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005504 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005505 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04005506 return;
5507 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04005508 checkCallerIsSameApp(pkg);
5509 }
5510
Chad Brubaker6b68f102017-01-27 13:39:00 -08005511 private boolean isCallerInstantApp(String pkg) {
5512 // System is always allowed to act for ephemeral apps.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005513 if (isCallerSystemOrPhone()) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08005514 return false;
5515 }
5516
5517 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
5518
5519 try {
5520 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0,
5521 UserHandle.getCallingUserId());
5522 if (ai == null) {
5523 throw new SecurityException("Unknown package " + pkg);
5524 }
5525 return ai.isInstantApp();
5526 } catch (RemoteException re) {
5527 throw new SecurityException("Unknown package " + pkg, re);
5528 }
5529
5530 }
5531
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005532 private void checkCallerIsSameApp(String pkg) {
John Spurlock7340fc82014-04-24 18:50:12 -04005533 final int uid = Binder.getCallingUid();
5534 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005535 ApplicationInfo ai = mPackageManager.getApplicationInfo(
John Spurlock7340fc82014-04-24 18:50:12 -04005536 pkg, 0, UserHandle.getCallingUserId());
Dan Sandler09afc2e2014-07-18 14:29:20 -04005537 if (ai == null) {
5538 throw new SecurityException("Unknown package " + pkg);
5539 }
John Spurlock7340fc82014-04-24 18:50:12 -04005540 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005541 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04005542 + pkg + " which is owned by uid " + ai.uid);
5543 }
5544 } catch (RemoteException re) {
5545 throw new SecurityException("Unknown package " + pkg + "\n" + re);
5546 }
5547 }
5548
John Spurlock32fe4c62014-10-02 12:16:02 -04005549 private static String callStateToString(int state) {
5550 switch (state) {
5551 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
5552 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
5553 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
5554 default: return "CALL_STATE_UNKNOWN_" + state;
5555 }
5556 }
5557
5558 private void listenForCallState() {
5559 TelephonyManager.from(getContext()).listen(new PhoneStateListener() {
5560 @Override
5561 public void onCallStateChanged(int state, String incomingNumber) {
5562 if (mCallState == state) return;
5563 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
5564 mCallState = state;
5565 }
5566 }, PhoneStateListener.LISTEN_CALL_STATE);
5567 }
5568
Christoph Studer05ad4822014-05-16 14:16:03 +02005569 /**
5570 * Generates a NotificationRankingUpdate from 'sbns', considering only
5571 * notifications visible to the given listener.
5572 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005573 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04005574 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04005575 final int N = mNotificationList.size();
5576 ArrayList<String> keys = new ArrayList<String>(N);
Christoph Studer1d599da2014-06-12 15:25:59 +02005577 ArrayList<String> interceptedKeys = new ArrayList<String>(N);
Chris Wrenbdf33762015-12-04 15:50:51 -05005578 ArrayList<Integer> importance = new ArrayList<>(N);
Julia Reynoldse46bb372016-03-17 11:05:58 -04005579 Bundle overrideGroupKeys = new Bundle();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005580 Bundle visibilityOverrides = new Bundle();
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005581 Bundle suppressedVisualEffects = new Bundle();
Chris Wrenbdf33762015-12-04 15:50:51 -05005582 Bundle explanation = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005583 Bundle channels = new Bundle();
Julia Reynolds22f02b32016-12-01 15:05:13 -05005584 Bundle overridePeople = new Bundle();
5585 Bundle snoozeCriteria = new Bundle();
Julia Reynolds924eed12017-01-19 09:52:07 -05005586 Bundle showBadge = new Bundle();
Julia Reynolds503ed942017-10-04 16:04:56 -04005587 Bundle userSentiment = new Bundle();
Chris Wren333a61c2014-05-28 16:40:57 -04005588 for (int i = 0; i < N; i++) {
5589 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02005590 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005591 continue;
5592 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005593 final String key = record.sbn.getKey();
5594 keys.add(key);
5595 importance.add(record.getImportance());
5596 if (record.getImportanceExplanation() != null) {
5597 explanation.putCharSequence(key, record.getImportanceExplanation());
5598 }
Chris Wren333a61c2014-05-28 16:40:57 -04005599 if (record.isIntercepted()) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005600 interceptedKeys.add(key);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05005601
Christoph Studer05ad4822014-05-16 14:16:03 +02005602 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005603 suppressedVisualEffects.putInt(key, record.getSuppressedVisualEffects());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005604 if (record.getPackageVisibilityOverride()
5605 != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
Chris Wrenbdf33762015-12-04 15:50:51 -05005606 visibilityOverrides.putInt(key, record.getPackageVisibilityOverride());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005607 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04005608 overrideGroupKeys.putString(key, record.sbn.getOverrideGroupKey());
Julia Reynolds924eed12017-01-19 09:52:07 -05005609 channels.putParcelable(key, record.getChannel());
Julia Reynolds22f02b32016-12-01 15:05:13 -05005610 overridePeople.putStringArrayList(key, record.getPeopleOverride());
5611 snoozeCriteria.putParcelableArrayList(key, record.getSnoozeCriteria());
Julia Reynolds924eed12017-01-19 09:52:07 -05005612 showBadge.putBoolean(key, record.canShowBadge());
Julia Reynolds503ed942017-10-04 16:04:56 -04005613 userSentiment.putInt(key, record.getUserSentiment());
Christoph Studer05ad4822014-05-16 14:16:03 +02005614 }
Chris Wrenbdf33762015-12-04 15:50:51 -05005615 final int M = keys.size();
5616 String[] keysAr = keys.toArray(new String[M]);
Christoph Studer1d599da2014-06-12 15:25:59 +02005617 String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
Chris Wrenbdf33762015-12-04 15:50:51 -05005618 int[] importanceAr = new int[M];
5619 for (int i = 0; i < M; i++) {
5620 importanceAr[i] = importance.get(i);
5621 }
Chris Wren3ad4e3a2014-09-02 17:23:51 -04005622 return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
Julia Reynolds22f02b32016-12-01 15:05:13 -05005623 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
Julia Reynolds503ed942017-10-04 16:04:56 -04005624 channels, overridePeople, snoozeCriteria, showBadge, userSentiment);
Christoph Studer05ad4822014-05-16 14:16:03 +02005625 }
5626
Julia Reynoldsda781472017-04-12 09:41:16 -04005627 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005628 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04005629 mCompanionManager = getCompanionManager();
5630 }
5631 // Companion mgr doesn't exist on all device types
5632 if (mCompanionManager == null) {
5633 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005634 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005635 long identity = Binder.clearCallingIdentity();
5636 try {
5637 List<String> associations = mCompanionManager.getAssociations(
5638 info.component.getPackageName(), info.userid);
5639 if (!ArrayUtils.isEmpty(associations)) {
5640 return true;
5641 }
5642 } catch (SecurityException se) {
5643 // Not a privileged listener
5644 } catch (RemoteException re) {
5645 Slog.e(TAG, "Cannot reach companion device service", re);
5646 } catch (Exception e) {
5647 Slog.e(TAG, "Cannot verify listener " + info, e);
5648 } finally {
5649 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005650 }
Julia Reynoldsda781472017-04-12 09:41:16 -04005651 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04005652 }
5653
Julia Reynolds727a7282017-04-13 10:54:01 -04005654 protected ICompanionDeviceManager getCompanionManager() {
5655 return ICompanionDeviceManager.Stub.asInterface(
5656 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
5657 }
5658
Christoph Studercef37cf2014-07-25 14:18:17 +02005659 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
5660 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
5661 return false;
5662 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07005663 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02005664 return true;
5665 }
5666
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00005667 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005668 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005669 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05005670 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005671 } catch (RemoteException re) {
5672 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00005673 } catch (IllegalArgumentException ex) {
5674 // Package not found.
5675 return false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005676 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00005677 }
5678
Julia Reynoldse1816412017-10-24 10:39:11 -04005679 private boolean canUseManagedServices() {
5680 return !mActivityManager.isLowRamDevice()
5681 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
5682 }
5683
Chris Wren47633422016-01-22 09:56:59 -05005684 private class TrimCache {
5685 StatusBarNotification heavy;
5686 StatusBarNotification sbnClone;
5687 StatusBarNotification sbnCloneLight;
5688
5689 TrimCache(StatusBarNotification sbn) {
5690 heavy = sbn;
5691 }
5692
5693 StatusBarNotification ForListener(ManagedServiceInfo info) {
5694 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
5695 if (sbnCloneLight == null) {
5696 sbnCloneLight = heavy.cloneLight();
5697 }
5698 return sbnCloneLight;
5699 } else {
5700 if (sbnClone == null) {
5701 sbnClone = heavy.clone();
5702 }
5703 return sbnClone;
5704 }
5705 }
5706 }
5707
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005708 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005709 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05005710
Julia Reynolds7380d872018-01-12 10:28:26 -05005711 public NotificationAssistants(Context context, Object lock, UserProfiles up,
5712 IPackageManager pm) {
5713 super(context, lock, up, pm);
Chris Wren51017d02015-12-15 15:34:46 -05005714 }
5715
5716 @Override
5717 protected Config getConfig() {
5718 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04005719 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005720 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005721 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005722 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
5723 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05005724 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005725 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05005726 return c;
5727 }
5728
5729 @Override
5730 protected IInterface asInterface(IBinder binder) {
5731 return INotificationListener.Stub.asInterface(binder);
5732 }
5733
5734 @Override
5735 protected boolean checkType(IInterface service) {
5736 return service instanceof INotificationListener;
5737 }
5738
5739 @Override
5740 protected void onServiceAdded(ManagedServiceInfo info) {
5741 mListeners.registerGuestService(info);
5742 }
5743
5744 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005745 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05005746 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
5747 mListeners.unregisterService(removed.service, removed.userid);
5748 }
Chris Wren47633422016-01-22 09:56:59 -05005749
Julia Reynoldsef934fd2018-02-01 14:39:17 -05005750 @Override
5751 public void onUserUnlocked(int user) {
5752 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
5753 rebindServices(true);
5754 }
5755
Chris Wren47633422016-01-22 09:56:59 -05005756 public void onNotificationEnqueued(final NotificationRecord r) {
5757 final StatusBarNotification sbn = r.sbn;
5758 TrimCache trimCache = new TrimCache(sbn);
5759
Chris Wren47633422016-01-22 09:56:59 -05005760 // There should be only one, but it's a list, so while we enforce
5761 // singularity elsewhere, we keep it general here, to avoid surprises.
Julia Reynolds00314d92017-04-14 10:01:24 -04005762 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
Chris Wren47633422016-01-22 09:56:59 -05005763 boolean sbnVisible = isVisibleToListener(sbn, info);
5764 if (!sbnVisible) {
5765 continue;
5766 }
5767
Chris Wren47633422016-01-22 09:56:59 -05005768 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Chris Wrene0ba7eb2016-03-04 17:30:43 -05005769 mHandler.post(new Runnable() {
Chris Wren47633422016-01-22 09:56:59 -05005770 @Override
5771 public void run() {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005772 notifyEnqueued(info, sbnToPost);
Chris Wren47633422016-01-22 09:56:59 -05005773 }
5774 });
5775 }
5776 }
5777
5778 private void notifyEnqueued(final ManagedServiceInfo info,
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005779 final StatusBarNotification sbn) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005780 final INotificationListener assistant = (INotificationListener) info.service;
Chris Wren47633422016-01-22 09:56:59 -05005781 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
5782 try {
Julia Reynoldsceecfcf2017-01-31 09:44:26 -05005783 assistant.onNotificationEnqueued(sbnHolder);
Chris Wren47633422016-01-22 09:56:59 -05005784 } catch (RemoteException ex) {
Julia Reynolds77b2cc92016-11-08 14:41:09 -05005785 Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Chris Wren47633422016-01-22 09:56:59 -05005786 }
5787 }
5788
Julia Reynolds79672302017-01-12 08:30:16 -05005789 /**
5790 * asynchronously notify the assistant that a notification has been snoozed until a
5791 * context
5792 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005793 @GuardedBy("mNotificationLock")
Julia Reynolds79672302017-01-12 08:30:16 -05005794 public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
5795 final String snoozeCriterionId) {
5796 TrimCache trimCache = new TrimCache(sbn);
Julia Reynolds00314d92017-04-14 10:01:24 -04005797 for (final ManagedServiceInfo info : getServices()) {
Julia Reynolds503ed942017-10-04 16:04:56 -04005798 boolean sbnVisible = isVisibleToListener(sbn, info);
5799 if (!sbnVisible) {
5800 continue;
5801 }
Julia Reynolds79672302017-01-12 08:30:16 -05005802 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
5803 mHandler.post(new Runnable() {
5804 @Override
5805 public void run() {
5806 final INotificationListener assistant =
5807 (INotificationListener) info.service;
5808 StatusBarNotificationHolder sbnHolder
5809 = new StatusBarNotificationHolder(sbnToPost);
5810 try {
5811 assistant.onNotificationSnoozedUntilContext(
5812 sbnHolder, snoozeCriterionId);
5813 } catch (RemoteException ex) {
5814 Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
5815 }
5816 }
5817 });
5818 }
5819 }
5820
Chris Wren47633422016-01-22 09:56:59 -05005821 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04005822 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05005823 }
Julia Reynolds7380d872018-01-12 10:28:26 -05005824
5825 protected void upgradeXml(final int xmlVersion, final int userId) {
5826 if (xmlVersion == 0) {
5827 // one time approval of the OOB assistant
5828 Slog.d(TAG, "Approving default notification assistant for user " + userId);
5829 readDefaultAssistant(userId);
5830 }
5831 }
Chris Wren51017d02015-12-15 15:34:46 -05005832 }
5833
John Spurlock7340fc82014-04-24 18:50:12 -04005834 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04005835 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04005836
Christoph Studerb82bc782014-08-20 14:29:43 +02005837 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
5838
Julia Reynoldsb852e562017-06-06 16:14:18 -04005839 public NotificationListeners(IPackageManager pm) {
5840 super(getContext(), mNotificationLock, mUserProfiles, pm);
5841
John Spurlock7340fc82014-04-24 18:50:12 -04005842 }
5843
5844 @Override
5845 protected Config getConfig() {
5846 Config c = new Config();
5847 c.caption = "notification listener";
5848 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005849 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04005850 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
5851 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
5852 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
5853 c.clientLabel = R.string.notification_listener_binding_label;
5854 return c;
5855 }
5856
5857 @Override
5858 protected IInterface asInterface(IBinder binder) {
5859 return INotificationListener.Stub.asInterface(binder);
5860 }
5861
5862 @Override
Chris Wren51017d02015-12-15 15:34:46 -05005863 protected boolean checkType(IInterface service) {
5864 return service instanceof INotificationListener;
5865 }
5866
5867 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04005868 public void onServiceAdded(ManagedServiceInfo info) {
5869 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04005870 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005871 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04005872 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005873 }
John Spurlock7340fc82014-04-24 18:50:12 -04005874 try {
Chris Wren333a61c2014-05-28 16:40:57 -04005875 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04005876 } catch (RemoteException e) {
5877 // we tried
5878 }
5879 }
5880
John Spurlock1fa865f2014-07-21 14:56:39 -04005881 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04005882 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04005883 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07005884 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04005885 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01005886 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04005887 }
Christoph Studerb82bc782014-08-20 14:29:43 +02005888 mLightTrimListeners.remove(removed);
5889 }
5890
Julia Reynolds88860ce2017-06-01 16:55:49 -04005891 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02005892 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
5893 if (trim == TRIM_LIGHT) {
5894 mLightTrimListeners.add(info);
5895 } else {
5896 mLightTrimListeners.remove(info);
5897 }
5898 }
5899
5900 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
5901 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04005902 }
5903
John Spurlock7340fc82014-04-24 18:50:12 -04005904 /**
5905 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02005906 *
5907 * <p>
5908 * Also takes care of removing a notification that has been visible to a listener before,
5909 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04005910 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005911 @GuardedBy("mNotificationLock")
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005912 public void notifyPostedLocked(NotificationRecord r, StatusBarNotification oldSbn) {
Christoph Studerb82bc782014-08-20 14:29:43 +02005913 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005914 StatusBarNotification sbn = r.sbn;
Chris Wren47633422016-01-22 09:56:59 -05005915 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02005916
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005917 Set<Uri> uris = r.getNotificationUris();
5918
Julia Reynolds00314d92017-04-14 10:01:24 -04005919 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005920 boolean sbnVisible = isVisibleToListener(sbn, info);
5921 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
5922 // This notification hasn't been and still isn't visible -> ignore.
5923 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005924 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005925 }
Chris Wren333a61c2014-05-28 16:40:57 -04005926 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02005927
5928 // This notification became invisible -> remove the old one.
5929 if (oldSbnVisible && !sbnVisible) {
5930 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
5931 mHandler.post(new Runnable() {
5932 @Override
5933 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04005934 notifyRemoved(
5935 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02005936 }
5937 });
Christoph Studer05ad4822014-05-16 14:16:03 +02005938 continue;
5939 }
Christoph Studercef37cf2014-07-25 14:18:17 +02005940
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005941 grantUriPermissions(uris, sbn.getUserId(), info.component.getPackageName(),
5942 info.userid);
5943
Chris Wren47633422016-01-22 09:56:59 -05005944 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005945 mHandler.post(new Runnable() {
5946 @Override
5947 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02005948 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02005949 }
5950 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005951 }
5952 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00005953
Julia Reynoldse0d711f2017-09-01 08:50:47 -04005954 private void grantUriPermissions(Set<Uri> uris, int notiUserId, String listenerPkg,
5955 int listenerUserId) {
5956 long ident = Binder.clearCallingIdentity();
5957 try {
5958 for (Uri uri : uris) {
5959 if (uri != null) {
5960 int sourceUserId = notiUserId == USER_ALL ? USER_SYSTEM
5961 : ContentProvider.getUserIdFromUri(uri, notiUserId);
5962 uri = ContentProvider.getUriWithoutUserId(uri);
5963 mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(),
5964 listenerPkg,
5965 uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId,
5966 listenerUserId == USER_ALL ? USER_SYSTEM : listenerUserId);
5967 }
5968 }
5969 } catch (RemoteException e) {
5970 Log.e(TAG, "Count not grant uri permission to " + listenerPkg, e);
5971 } finally {
5972 Binder.restoreCallingIdentity(ident);
5973 }
5974 }
5975
John Spurlock7340fc82014-04-24 18:50:12 -04005976 /**
5977 * asynchronously notify all listeners about a removed notification
5978 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005979 @GuardedBy("mNotificationLock")
Julia Reynolds503ed942017-10-04 16:04:56 -04005980 public void notifyRemovedLocked(StatusBarNotification sbn, int reason,
5981 NotificationStats notificationStats) {
John Spurlock7340fc82014-04-24 18:50:12 -04005982 // make a copy in case changes are made to the underlying Notification object
5983 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
5984 // notification
5985 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04005986 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02005987 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02005988 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04005989 }
Julia Reynolds503ed942017-10-04 16:04:56 -04005990 // Only assistants can get stats
5991 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
5992 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04005993 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02005994 mHandler.post(new Runnable() {
5995 @Override
5996 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04005997 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02005998 }
5999 });
Chris Wrenf9536642014-04-17 10:01:54 -04006000 }
6001 }
6002
6003 /**
6004 * asynchronously notify all listeners about a reordering of notifications
Chris Wrenf9536642014-04-17 10:01:54 -04006005 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006006 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006007 public void notifyRankingUpdateLocked() {
Julia Reynolds00314d92017-04-14 10:01:24 -04006008 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02006009 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6010 continue;
6011 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006012 final NotificationRankingUpdate update = makeRankingUpdateLocked(serviceInfo);
John Spurlock7340fc82014-04-24 18:50:12 -04006013 mHandler.post(new Runnable() {
6014 @Override
6015 public void run() {
Chris Wren333a61c2014-05-28 16:40:57 -04006016 notifyRankingUpdate(serviceInfo, update);
John Spurlock7340fc82014-04-24 18:50:12 -04006017 }
6018 });
Kenny Guya263e4e2014-03-03 18:24:03 +00006019 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006020 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006021
Julia Reynolds88860ce2017-06-01 16:55:49 -04006022 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04006023 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006024 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006025 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6026 continue;
6027 }
6028 mHandler.post(new Runnable() {
6029 @Override
6030 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006031 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006032 }
6033 });
6034 }
6035 }
6036
Christoph Studer85a384b2014-08-27 20:16:15 +02006037 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006038 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006039 if (!serviceInfo.isEnabledForCurrentProfiles()) {
6040 continue;
6041 }
6042 mHandler.post(new Runnable() {
6043 @Override
6044 public void run() {
6045 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
6046 }
6047 });
6048 }
6049 }
6050
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006051 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006052 final NotificationChannel channel, final int modificationType) {
6053 if (channel == null) {
6054 return;
6055 }
6056 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006057 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006058 continue;
6059 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006060
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006061 BackgroundThread.getHandler().post(() -> {
6062 if (hasCompanionDevice(serviceInfo)) {
6063 notifyNotificationChannelChanged(
6064 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006065 }
6066 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006067 }
6068 }
6069
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006070 protected void notifyNotificationChannelGroupChanged(
6071 final String pkg, final UserHandle user, final NotificationChannelGroup group,
6072 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006073 if (group == null) {
6074 return;
6075 }
6076 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04006077 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006078 continue;
6079 }
Julia Reynolds018aa622017-04-20 11:31:30 -04006080
Eugene Suslaa25d17f2017-08-24 11:28:08 -07006081 BackgroundThread.getHandler().post(() -> {
6082 if (hasCompanionDevice(serviceInfo)) {
6083 notifyNotificationChannelGroupChanged(
6084 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04006085 }
6086 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006087 }
6088 }
6089
Christoph Studercef37cf2014-07-25 14:18:17 +02006090 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02006091 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04006092 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006093 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006094 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07006095 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04006096 } catch (RemoteException ex) {
6097 Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
6098 }
6099 }
6100
Christoph Studercef37cf2014-07-25 14:18:17 +02006101 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04006102 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04006103 if (!info.enabledAndUserMatches(sbn.getUserId())) {
6104 return;
6105 }
Christoph Studer05ad4822014-05-16 14:16:03 +02006106 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006107 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04006108 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04006109 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04006110 } catch (RemoteException ex) {
6111 Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04006112 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006113 }
Chris Wrenf9536642014-04-17 10:01:54 -04006114
Christoph Studer05ad4822014-05-16 14:16:03 +02006115 private void notifyRankingUpdate(ManagedServiceInfo info,
6116 NotificationRankingUpdate rankingUpdate) {
6117 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04006118 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02006119 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04006120 } catch (RemoteException ex) {
6121 Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
6122 }
6123 }
John Spurlock1fa865f2014-07-21 14:56:39 -04006124
John Spurlockd8afe3c2014-08-01 14:04:07 -04006125 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04006126 final INotificationListener listener = (INotificationListener) info.service;
6127 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006128 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006129 } catch (RemoteException ex) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006130 Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04006131 }
6132 }
Justin Koh38156c52014-06-04 13:57:49 -07006133
Christoph Studer85a384b2014-08-27 20:16:15 +02006134 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
6135 int interruptionFilter) {
6136 final INotificationListener listener = (INotificationListener) info.service;
6137 try {
6138 listener.onInterruptionFilterChanged(interruptionFilter);
6139 } catch (RemoteException ex) {
6140 Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
6141 }
6142 }
6143
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006144 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006145 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006146 final int modificationType) {
6147 final INotificationListener listener = (INotificationListener) info.service;
6148 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006149 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006150 } catch (RemoteException ex) {
6151 Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
6152 }
6153 }
6154
6155 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006156 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006157 final int modificationType) {
6158 final INotificationListener listener = (INotificationListener) info.service;
6159 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04006160 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04006161 } catch (RemoteException ex) {
6162 Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
6163 }
6164 }
6165
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006166 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07006167 if (packageName == null) {
6168 return false;
6169 }
6170 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006171 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04006172 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07006173 if (packageName.equals(serviceInfo.component.getPackageName())) {
6174 return true;
6175 }
6176 }
6177 }
6178 return false;
6179 }
Kenny Guya263e4e2014-03-03 18:24:03 +00006180 }
John Spurlock25e2d242014-06-27 13:58:23 -04006181
6182 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04006183 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006184 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04006185 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04006186 public long since;
6187 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04006188 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006189 public boolean proto = false;
John Spurlock25e2d242014-06-27 13:58:23 -04006190
Kweku Adams887f09c2017-11-13 17:12:20 -08006191 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04006192 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04006193 final DumpFilter filter = new DumpFilter();
6194 for (int ai = 0; ai < args.length; ai++) {
6195 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07006196 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05006197 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07006198 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04006199 filter.redact = false;
6200 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
6201 if (ai < args.length-1) {
6202 ai++;
6203 filter.pkgFilter = args[ai].trim().toLowerCase();
6204 if (filter.pkgFilter.isEmpty()) {
6205 filter.pkgFilter = null;
6206 } else {
6207 filter.filtered = true;
6208 }
6209 }
6210 } else if ("--zen".equals(a) || "zen".equals(a)) {
6211 filter.filtered = true;
6212 filter.zen = true;
6213 } else if ("--stats".equals(a)) {
6214 filter.stats = true;
6215 if (ai < args.length-1) {
6216 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01006217 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04006218 } else {
6219 filter.since = 0;
6220 }
6221 }
John Spurlock25e2d242014-06-27 13:58:23 -04006222 }
Dan Sandlera1770312015-07-10 13:59:29 -04006223 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04006224 }
6225
6226 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04006227 if (!filtered) return true;
6228 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04006229 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04006230 }
6231
6232 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04006233 if (!filtered) return true;
6234 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04006235 }
6236
6237 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04006238 if (!filtered) return true;
6239 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04006240 }
6241
6242 @Override
6243 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04006244 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04006245 }
6246 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07006247
6248 /**
6249 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
6250 * binder without sending large amounts of data over a oneway transaction.
6251 */
6252 private static final class StatusBarNotificationHolder
6253 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07006254 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006255
6256 public StatusBarNotificationHolder(StatusBarNotification value) {
6257 mValue = value;
6258 }
6259
Griff Hazene9aac5f2014-09-05 20:04:09 -07006260 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07006261 @Override
6262 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07006263 StatusBarNotification value = mValue;
6264 mValue = null;
6265 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07006266 }
6267 }
John Spurlock7c74f782015-06-04 13:01:42 -04006268
Julia Reynoldsb852e562017-06-06 16:14:18 -04006269 private class ShellCmd extends ShellCommand {
6270 public static final String USAGE = "help\n"
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006271 + "allow_listener COMPONENT [user_id]\n"
6272 + "disallow_listener COMPONENT [user_id]\n"
Julia Reynolds7380d872018-01-12 10:28:26 -05006273 + "allow_assistant COMPONENT\n"
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006274 + "remove_assistant COMPONENT\n"
Julia Reynoldsb852e562017-06-06 16:14:18 -04006275 + "allow_dnd PACKAGE\n"
6276 + "disallow_dnd PACKAGE";
John Spurlock7c74f782015-06-04 13:01:42 -04006277
Julia Reynoldsb852e562017-06-06 16:14:18 -04006278 @Override
6279 public int onCommand(String cmd) {
Felipe Leme68d80412017-07-14 11:18:08 -07006280 if (cmd == null) {
6281 return handleDefaultCommands(cmd);
6282 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006283 final PrintWriter pw = getOutPrintWriter();
Julia Reynoldsea6c4482015-08-13 09:01:33 -04006284 try {
Julia Reynoldsb852e562017-06-06 16:14:18 -04006285 switch (cmd) {
6286 case "allow_dnd": {
6287 getBinderService().setNotificationPolicyAccessGranted(
6288 getNextArgRequired(), true);
John Spurlock7c74f782015-06-04 13:01:42 -04006289 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04006290 break;
6291
6292 case "disallow_dnd": {
6293 getBinderService().setNotificationPolicyAccessGranted(
6294 getNextArgRequired(), false);
6295 }
6296 break;
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006297 case "allow_listener": {
6298 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6299 if (cn == null) {
6300 pw.println("Invalid listener - must be a ComponentName");
6301 return -1;
6302 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006303 String userId = getNextArg();
6304 if (userId == null) {
6305 getBinderService().setNotificationListenerAccessGranted(cn, true);
6306 } else {
6307 getBinderService().setNotificationListenerAccessGrantedForUser(
6308 cn, Integer.parseInt(userId), true);
6309 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006310 }
6311 break;
6312 case "disallow_listener": {
6313 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6314 if (cn == null) {
6315 pw.println("Invalid listener - must be a ComponentName");
6316 return -1;
6317 }
Jaewan Kim3c45c4c2017-09-21 23:32:11 +09006318 String userId = getNextArg();
6319 if (userId == null) {
6320 getBinderService().setNotificationListenerAccessGranted(cn, false);
6321 } else {
6322 getBinderService().setNotificationListenerAccessGrantedForUser(
6323 cn, Integer.parseInt(userId), false);
6324 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006325 }
6326 break;
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006327 case "allow_assistant": {
6328 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6329 if (cn == null) {
6330 pw.println("Invalid assistant - must be a ComponentName");
6331 return -1;
6332 }
6333 getBinderService().setNotificationAssistantAccessGranted(cn, true);
6334 }
6335 break;
6336 case "disallow_assistant": {
6337 ComponentName cn = ComponentName.unflattenFromString(getNextArgRequired());
6338 if (cn == null) {
6339 pw.println("Invalid assistant - must be a ComponentName");
6340 return -1;
6341 }
6342 getBinderService().setNotificationAssistantAccessGranted(cn, false);
6343 }
6344 break;
Julia Reynoldsb852e562017-06-06 16:14:18 -04006345
6346 default:
6347 return handleDefaultCommands(cmd);
John Spurlock7c74f782015-06-04 13:01:42 -04006348 }
Julia Reynoldsb71f1d32017-06-23 13:32:09 -04006349 } catch (Exception e) {
6350 pw.println("Error occurred. Check logcat for details. " + e.getMessage());
Julia Reynoldsb852e562017-06-06 16:14:18 -04006351 Slog.e(TAG, "Error running shell command", e);
John Spurlock7c74f782015-06-04 13:01:42 -04006352 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04006353 return 0;
John Spurlock7c74f782015-06-04 13:01:42 -04006354 }
6355
Julia Reynoldsb852e562017-06-06 16:14:18 -04006356 @Override
6357 public void onHelp() {
6358 getOutPrintWriter().println(USAGE);
John Spurlock7c74f782015-06-04 13:01:42 -04006359 }
6360 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006361}