blob: faac78d68879b50250514a152eee259bbef681e3 [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
Beverly58b24532018-10-02 09:08:23 -040019import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
Mady Mellorbe797962019-04-01 16:04:24 -070020import static android.app.Notification.CATEGORY_CALL;
Mady Mellor49b1bf12019-03-29 12:00:02 -070021import static android.app.Notification.FLAG_AUTOGROUP_SUMMARY;
22import static android.app.Notification.FLAG_BUBBLE;
Julia Reynoldse5c60452018-04-30 14:41:36 -040023import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
Mady Mellor49b1bf12019-03-29 12:00:02 -070024import static android.app.Notification.FLAG_NO_CLEAR;
25import static android.app.Notification.FLAG_ONGOING_EVENT;
Mady Mellor66efd5e2019-05-15 13:38:11 -070026import static android.app.Notification.FLAG_ONLY_ALERT_ONCE;
Julia Reynoldsfc9767b2018-01-22 17:45:16 -050027import static android.app.NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050028import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED;
29import static android.app.NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED;
Julia Reynolds4afe2642019-05-01 08:42:24 -040030import static android.app.NotificationManager.ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED;
Julia Reynolds8617e4e2017-09-18 16:52:37 -040031import static android.app.NotificationManager.IMPORTANCE_LOW;
Julia Reynolds7c96b582017-05-25 12:35:36 -040032import static android.app.NotificationManager.IMPORTANCE_MIN;
Julia Reynolds85769912016-10-25 09:08:57 -040033import static android.app.NotificationManager.IMPORTANCE_NONE;
Julia Reynoldsa94365d2019-04-09 10:48:43 -040034import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -050035import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
36import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
37import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
38import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
39import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
40import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
41import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
42import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
43import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
44import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
Amith Yamasanie5bfeee2018-09-05 18:52:35 -070045import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
46import static android.content.Context.BIND_AUTO_CREATE;
47import static android.content.Context.BIND_FOREGROUND_SERVICE;
Amith Yamasani5016a782019-06-17 16:20:24 -070048import static android.content.Context.BIND_NOT_PERCEPTIBLE;
Mady Mellorca0c24c2019-05-16 16:14:32 -070049import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -050050import static android.content.pm.PackageManager.FEATURE_LEANBACK;
51import static android.content.pm.PackageManager.FEATURE_TELEVISION;
Julia Reynoldse7ca31b2019-04-25 15:41:47 -040052import static android.content.pm.PackageManager.MATCH_ALL;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -040053import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
54import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
Julia Reynolds4db59552017-06-30 13:34:01 -040055import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Vishnu Naire3e4d252018-03-01 11:26:57 -080056import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
57import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
Julia Reynolds88a879f2017-07-26 17:06:46 -040058import static android.os.UserHandle.USER_NULL;
Julia Reynoldse0d711f2017-09-01 08:50:47 -040059import static android.os.UserHandle.USER_SYSTEM;
Gus Prevas7306b902018-12-11 10:57:06 -050060import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050061import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
Gus Prevas7306b902018-12-11 10:57:06 -050062import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS;
63import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED;
64import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
65import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050066import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL;
67import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL_ALL;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040068import static android.service.notification.NotificationListenerService.REASON_CANCEL;
69import static android.service.notification.NotificationListenerService.REASON_CANCEL_ALL;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -050070import static android.service.notification.NotificationListenerService.REASON_CHANNEL_BANNED;
Julia Reynoldsf619bc52017-03-17 08:32:23 -040071import static android.service.notification.NotificationListenerService.REASON_CLICK;
72import static android.service.notification.NotificationListenerService.REASON_ERROR;
Gus Prevas7306b902018-12-11 10:57:06 -050073import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050074import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL;
75import static android.service.notification.NotificationListenerService.REASON_LISTENER_CANCEL_ALL;
76import static android.service.notification.NotificationListenerService.REASON_PACKAGE_BANNED;
77import static android.service.notification.NotificationListenerService.REASON_PACKAGE_CHANGED;
78import static android.service.notification.NotificationListenerService.REASON_PACKAGE_SUSPENDED;
79import static android.service.notification.NotificationListenerService.REASON_PROFILE_TURNED_OFF;
80import static android.service.notification.NotificationListenerService.REASON_SNOOZED;
Julia Reynolds2a128742016-11-28 14:29:25 -050081import static android.service.notification.NotificationListenerService.REASON_TIMEOUT;
Julia Reynolds3aa5f1e2016-11-09 15:43:49 -050082import static android.service.notification.NotificationListenerService.REASON_UNAUTOBUNDLED;
83import static android.service.notification.NotificationListenerService.REASON_USER_STOPPED;
Christoph Studerb82bc782014-08-20 14:29:43 +020084import static android.service.notification.NotificationListenerService.TRIM_FULL;
85import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
Mady Mellorca0c24c2019-05-16 16:14:32 -070086import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
87import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
88import static android.util.StatsLogInternal.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
Wale Ogunwaleac2561e2016-11-01 15:43:46 -070089import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
svetoslavganov75986cf2009-05-14 22:28:01 -070090
Michal Karpinskiac116df2018-12-10 17:51:42 +000091import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
92import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER;
Michal Karpinskic8aa91b2019-01-10 16:45:59 +000093import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER;
Vishnu Naire3e4d252018-03-01 11:26:57 -080094import static com.android.server.utils.PriorityDump.PRIORITY_ARG;
95import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
96import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
97
Chris Wren51017d02015-12-15 15:34:46 -050098import android.Manifest;
Zimuzob3b9c262018-10-31 11:54:20 +000099import android.Manifest.permission;
Julia Reynolds0c245002019-03-27 16:10:11 -0400100import android.annotation.CallbackExecutor;
Julia Reynoldsa78cdff2017-04-26 10:19:25 -0400101import android.annotation.NonNull;
Wei Liu97e56662016-03-04 10:52:33 -0800102import android.annotation.Nullable;
Dianne Hackborn41203752012-08-31 14:05:51 -0700103import android.app.ActivityManager;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700104import android.app.ActivityManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500105import android.app.AlarmManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400106import android.app.AppGlobals;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500107import android.app.AppOpsManager;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400108import android.app.AutomaticZenRule;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import android.app.IActivityManager;
110import android.app.INotificationManager;
111import android.app.ITransientNotification;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700112import android.app.IUriGrantsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import android.app.Notification;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -0400114import android.app.NotificationChannel;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500115import android.app.NotificationChannelGroup;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500116import android.app.NotificationManager;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500117import android.app.NotificationManager.Policy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118import android.app.PendingIntent;
Mady Mellorbe797962019-04-01 16:04:24 -0700119import android.app.Person;
Mady Mellora10448e2019-04-26 13:50:58 -0700120import android.app.RemoteInput;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121import android.app.StatusBarManager;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700122import android.app.UriGrantsManager;
Jason Parks50322ff2018-03-27 10:23:33 -0500123import android.app.admin.DeviceAdminInfo;
124import android.app.admin.DevicePolicyManagerInternal;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500125import android.app.backup.BackupManager;
Julia Reynolds0c245002019-03-27 16:10:11 -0400126import android.app.role.OnRoleHoldersChangedListener;
127import android.app.role.RoleManager;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700128import android.app.usage.UsageEvents;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700129import android.app.usage.UsageStatsManagerInternal;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400130import android.companion.ICompanionDeviceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131import android.content.BroadcastReceiver;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700132import android.content.ComponentName;
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400133import android.content.ContentProvider;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700134import android.content.ContentResolver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135import android.content.Context;
136import android.content.Intent;
137import android.content.IntentFilter;
Mady Mellorca0c24c2019-05-16 16:14:32 -0700138import android.content.pm.ActivityInfo;
John Spurlock7340fc82014-04-24 18:50:12 -0400139import android.content.pm.ApplicationInfo;
Kenny Guy70058402014-10-28 20:45:06 +0000140import android.content.pm.IPackageManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141import android.content.pm.PackageManager;
142import android.content.pm.PackageManager.NameNotFoundException;
Julia Reynoldsb40cd092019-01-25 09:35:02 -0500143import android.content.pm.PackageManagerInternal;
Christoph Studercee44ba2014-05-20 18:36:43 +0200144import android.content.pm.ParceledListSlice;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400145import android.content.pm.UserInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146import android.content.res.Resources;
Dianne Hackborn1dac2772009-06-26 18:16:48 -0700147import android.database.ContentObserver;
Beverly5d463b62017-07-26 14:13:40 -0400148import android.media.AudioAttributes;
svetoslavganov75986cf2009-05-14 22:28:01 -0700149import android.media.AudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500150import android.media.AudioManagerInternal;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700151import android.media.IRingtonePlayer;
Kenny Guy23991102018-04-05 21:18:38 +0100152import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154import android.os.Binder;
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -0400155import android.os.Build;
John Spurlock2b122f42014-08-27 16:29:47 -0400156import android.os.Bundle;
John Spurlock056c5192014-04-20 21:52:01 -0400157import android.os.Environment;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158import android.os.Handler;
Chris Wrenf9536642014-04-17 10:01:54 -0400159import android.os.HandlerThread;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160import android.os.IBinder;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800161import android.os.IDeviceIdleController;
John Spurlock7340fc82014-04-24 18:50:12 -0400162import android.os.IInterface;
Chris Wrenf9536642014-04-17 10:01:54 -0400163import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164import android.os.Message;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -0700165import android.os.Process;
svetoslavganov75986cf2009-05-14 22:28:01 -0700166import android.os.RemoteException;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400167import android.os.ResultReceiver;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400168import android.os.ServiceManager;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400169import android.os.ShellCallback;
Chris Wrenc8673a82016-05-17 17:11:29 -0400170import android.os.SystemClock;
Selim Cinekb5605e52015-02-20 18:21:41 +0100171import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700172import android.os.UserHandle;
Julia Reynolds0c245002019-03-27 16:10:11 -0400173import android.os.UserManager;
Michael Wright71216972017-01-31 18:33:54 +0000174import android.os.VibrationEffect;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500175import android.os.Vibrator;
Tony Mak9a3c1f12019-03-04 16:04:42 +0000176import android.provider.DeviceConfig;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177import android.provider.Settings;
Julia Reynoldse46bb372016-03-17 11:05:58 -0400178import android.service.notification.Adjustment;
Chris Wren333a61c2014-05-28 16:40:57 -0400179import android.service.notification.Condition;
John Spurlock7340fc82014-04-24 18:50:12 -0400180import android.service.notification.IConditionProvider;
Chris Wren333a61c2014-05-28 16:40:57 -0400181import android.service.notification.INotificationListener;
Griff Hazen84a00ea2014-09-02 17:10:47 -0700182import android.service.notification.IStatusBarNotificationHolder;
Kweku Adams93304b62017-09-20 17:03:00 -0700183import android.service.notification.ListenersDisablingEffectsProto;
Julia Reynolds77b2cc92016-11-08 14:41:09 -0500184import android.service.notification.NotificationAssistantService;
John Spurlock7340fc82014-04-24 18:50:12 -0400185import android.service.notification.NotificationListenerService;
Christoph Studer05ad4822014-05-16 14:16:03 +0200186import android.service.notification.NotificationRankingUpdate;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500187import android.service.notification.NotificationRecordProto;
188import android.service.notification.NotificationServiceDumpProto;
Julia Reynolds503ed942017-10-04 16:04:56 -0400189import android.service.notification.NotificationStats;
Julia Reynolds22f02b32016-12-01 15:05:13 -0500190import android.service.notification.SnoozeCriterion;
Daniel Sandler5feceeb2013-03-22 18:29:23 -0700191import android.service.notification.StatusBarNotification;
John Spurlock056c5192014-04-20 21:52:01 -0400192import android.service.notification.ZenModeConfig;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500193import android.service.notification.ZenModeProto;
John Spurlock32fe4c62014-10-02 12:16:02 -0400194import android.telephony.PhoneStateListener;
Daniel Sandlere96ffb12010-03-11 13:38:06 -0500195import android.telephony.TelephonyManager;
svetoslavganov75986cf2009-05-14 22:28:01 -0700196import android.text.TextUtils;
John Spurlocka4294292014-03-24 18:02:32 -0400197import android.util.ArrayMap;
John Spurlock1fa865f2014-07-21 14:56:39 -0400198import android.util.ArraySet;
Dianne Hackborn39606a02012-07-31 17:54:35 -0700199import android.util.AtomicFile;
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400200import android.util.IntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201import android.util.Log;
Julia Reynoldse7ca31b2019-04-25 15:41:47 -0400202import android.util.Pair;
Andy Stadler110988c2010-12-03 14:29:16 -0800203import android.util.Slog;
Bryce Lee7219ada2016-04-08 10:54:23 -0700204import android.util.SparseArray;
Mady Mellorca0c24c2019-05-16 16:14:32 -0700205import android.util.StatsLog;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400206import android.util.Xml;
Julia Reynoldsc9842c12017-02-07 12:46:41 -0500207import android.util.proto.ProtoOutputStream;
svetoslavganov75986cf2009-05-14 22:28:01 -0700208import android.view.accessibility.AccessibilityEvent;
209import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210import android.widget.Toast;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000211
Scott Greenwald9a05b312013-06-28 00:37:54 -0400212import com.android.internal.R;
Julia Reynolds88860ce2017-06-01 16:55:49 -0400213import com.android.internal.annotations.GuardedBy;
Chris Wren93bb8b82016-03-29 14:35:05 -0400214import com.android.internal.annotations.VisibleForTesting;
Tony Mak9a3c1f12019-03-04 16:04:42 +0000215import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
Chris Wren9eb5e102017-01-26 13:15:06 -0500216import com.android.internal.logging.MetricsLogger;
Julia Reynolds520df6e2017-02-13 09:05:10 -0500217import com.android.internal.logging.nano.MetricsProto;
Chris Wren9eb5e102017-01-26 13:15:06 -0500218import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Beverly70dcd002018-03-29 17:09:16 -0400219import com.android.internal.notification.SystemNotificationChannels;
Eugene Suslaa25d17f2017-08-24 11:28:08 -0700220import com.android.internal.os.BackgroundThread;
Julia Reynoldsb0405592018-11-26 17:01:13 -0500221import com.android.internal.os.SomeArgs;
Chris Wrend1dbc922015-06-19 17:51:16 -0400222import com.android.internal.statusbar.NotificationVisibility;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400223import com.android.internal.util.ArrayUtils;
Fabian Kozynskid9425662019-01-29 13:08:30 -0500224import com.android.internal.util.CollectionUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600225import com.android.internal.util.DumpUtils;
John Spurlock056c5192014-04-20 21:52:01 -0400226import com.android.internal.util.FastXmlSerializer;
Julia Reynoldsa47a27f2015-08-24 08:31:47 -0400227import com.android.internal.util.Preconditions;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400228import com.android.internal.util.XmlUtils;
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500229import com.android.internal.util.function.TriPredicate;
Felipe Lemea1b79bf2016-05-24 13:06:54 -0700230import com.android.server.DeviceIdleController;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800231import com.android.server.EventLogTags;
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500232import com.android.server.IoThread;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700233import com.android.server.LocalServices;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800234import com.android.server.SystemService;
235import com.android.server.lights.Light;
236import com.android.server.lights.LightsManager;
John Spurlock7340fc82014-04-24 18:50:12 -0400237import com.android.server.notification.ManagedServices.ManagedServiceInfo;
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -0500238import com.android.server.notification.ManagedServices.UserProfiles;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400239import com.android.server.pm.PackageManagerService;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700240import com.android.server.policy.PhoneWindowManager;
John Spurlockb408e8e2014-04-23 21:12:45 -0400241import com.android.server.statusbar.StatusBarManagerInternal;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700242import com.android.server.uri.UriGrantsManagerInternal;
Adrian Roose99bc052017-11-20 17:55:31 +0100243import com.android.server.wm.WindowManagerInternal;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800244
John Spurlockb408e8e2014-04-23 21:12:45 -0400245import libcore.io.IoUtils;
Rubin Xu7eadc1b2016-02-01 16:13:45 +0000246
Chris Wrene4b38802015-07-07 15:54:19 -0400247import org.json.JSONException;
248import org.json.JSONObject;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700249import org.xmlpull.v1.XmlPullParser;
250import org.xmlpull.v1.XmlPullParserException;
John Spurlock056c5192014-04-20 21:52:01 -0400251import org.xmlpull.v1.XmlSerializer;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700252
John Spurlock35ef0a62015-05-28 11:24:10 -0400253import java.io.ByteArrayInputStream;
254import java.io.ByteArrayOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400255import java.io.File;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256import java.io.FileDescriptor;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400257import java.io.FileNotFoundException;
John Spurlock056c5192014-04-20 21:52:01 -0400258import java.io.FileOutputStream;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400259import java.io.IOException;
John Spurlock35ef0a62015-05-28 11:24:10 -0400260import java.io.InputStream;
261import java.io.OutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262import java.io.PrintWriter;
Wojciech Staszkiewicz9e9e2e72015-05-08 14:58:46 +0100263import java.nio.charset.StandardCharsets;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500264import java.util.ArrayDeque;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265import java.util.ArrayList;
Michael Wrightbc4d0d92017-03-23 18:57:57 +0000266import java.util.Arrays;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500267import java.util.Iterator;
John Spurlock7c74f782015-06-04 13:01:42 -0400268import java.util.List;
Christoph Studer265c1052014-07-23 17:14:33 +0200269import java.util.Map.Entry;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500270import java.util.Objects;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400271import java.util.Set;
Julia Reynolds0c245002019-03-27 16:10:11 -0400272import java.util.concurrent.Executor;
Chris Wren51017d02015-12-15 15:34:46 -0500273import java.util.concurrent.TimeUnit;
Tony Makeda84a72018-11-19 17:01:32 +0000274import java.util.function.BiConsumer;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400275
Daniel Sandlerd0a2f862010-08-03 15:29:31 -0400276/** {@hide} */
Adam Lesinski182f73f2013-12-05 16:48:06 -0800277public class NotificationManagerService extends SystemService {
278 static final String TAG = "NotificationService";
Christoph Studer1f32c652014-11-26 15:32:20 +0100279 static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Selim Cinek40412492015-12-08 18:03:22 -0800280 public static final boolean ENABLE_CHILD_NOTIFICATIONS
281 = SystemProperties.getBoolean("debug.child_notifs", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282
Dan Sandler7d67bd42018-05-15 14:06:38 -0400283 static final boolean DEBUG_INTERRUPTIVENESS = SystemProperties.getBoolean(
284 "debug.notification.interruptiveness", false);
285
Julia Reynolds3e9bd482019-05-31 09:19:15 -0400286 static final int MAX_PACKAGE_NOTIFICATIONS = 25;
Julia Reynolds6ad0aec2017-07-05 08:47:03 -0400287 static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
Joe Onoratobd73d012010-06-04 11:44:54 -0700288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 // message codes
Robert Carr997427342018-02-28 18:06:10 -0800290 static final int MESSAGE_DURATION_REACHED = 2;
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500291 // 3: removed to a different handler
Chris Wren51017d02015-12-15 15:34:46 -0500292 static final int MESSAGE_SEND_RANKING_UPDATE = 4;
293 static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
294 static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
Robert Carr997427342018-02-28 18:06:10 -0800295 static final int MESSAGE_FINISH_TOKEN_TIMEOUT = 7;
Julia Reynoldsb0405592018-11-26 17:01:13 -0500296 static final int MESSAGE_ON_PACKAGE_CHANGED = 8;
Chris Wren51017d02015-12-15 15:34:46 -0500297
298 // ranking thread messages
299 private static final int MESSAGE_RECONSIDER_RANKING = 1000;
300 private static final int MESSAGE_RANKING_SORT = 1001;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700302 static final int LONG_DELAY = PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800303 static final int SHORT_DELAY = 2000; // 2 seconds
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800304
Robert Carr3406d462018-03-15 16:19:07 -0700305 // 1 second past the ANR timeout.
306 static final int FINISH_TOKEN_TIMEOUT = 11 * 1000;
307
Adam Lesinski182f73f2013-12-05 16:48:06 -0800308 static final long[] DEFAULT_VIBRATE_PATTERN = {0, 250, 250, 250};
Christoph Studer265c1052014-07-23 17:14:33 +0200309
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500310 static final long SNOOZE_UNTIL_UNSPECIFIED = -1;
311
Adam Lesinski182f73f2013-12-05 16:48:06 -0800312 static final int VIBRATE_PATTERN_MAXLEN = 8 * 2 + 1; // up to eight bumps
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313
Adam Lesinski182f73f2013-12-05 16:48:06 -0800314 static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_NOTIFICATION;
Daniel Sandler526fa0e2012-12-04 14:51:50 -0500315
Adam Lesinski182f73f2013-12-05 16:48:06 -0800316 static final boolean ENABLE_BLOCKED_TOASTS = true;
Daniel Sandler0da673f2012-04-11 12:33:16 -0400317
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500318 static final String[] DEFAULT_ALLOWED_ADJUSTMENTS = new String[] {
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500319 Adjustment.KEY_CONTEXTUAL_ACTIONS,
Julia Reynolds66500042019-04-19 11:23:55 -0400320 Adjustment.KEY_TEXT_REPLIES};
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500321
Julia Reynolds0c245002019-03-27 16:10:11 -0400322 static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
323 RoleManager.ROLE_DIALER,
Julia Reynolds0c245002019-03-27 16:10:11 -0400324 RoleManager.ROLE_EMERGENCY
325 };
326
Christoph Studer12aeda82014-09-23 19:08:56 +0200327 // When #matchesCallFilter is called from the ringer, wait at most
328 // 3s to resolve the contacts. This timeout is required since
329 // ContactsProvider might take a long time to start up.
330 //
331 // Return STARRED_CONTACT when the timeout is hit in order to avoid
332 // missed calls in ZEN mode "Important".
333 static final int MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS = 3000;
334 static final float MATCHES_CALL_FILTER_TIMEOUT_AFFINITY =
335 ValidateNotificationPeople.STARRED_CONTACT;
336
Christoph Studer265c1052014-07-23 17:14:33 +0200337 /** notification_enqueue status value for a newly enqueued notification. */
338 private static final int EVENTLOG_ENQUEUE_STATUS_NEW = 0;
339
340 /** notification_enqueue status value for an existing notification. */
341 private static final int EVENTLOG_ENQUEUE_STATUS_UPDATE = 1;
342
343 /** notification_enqueue status value for an ignored notification. */
344 private static final int EVENTLOG_ENQUEUE_STATUS_IGNORED = 2;
Chris Wrenc8673a82016-05-17 17:11:29 -0400345 private static final long MIN_PACKAGE_OVERRATE_LOG_INTERVAL = 5000; // milliseconds
Christoph Studer265c1052014-07-23 17:14:33 +0200346
Julia Reynolds4b82f6d2017-01-04 10:47:41 -0500347 private static final long DELAY_FOR_ASSISTANT_TIME = 100;
348
Julia Reynolds2a128742016-11-28 14:29:25 -0500349 private static final String ACTION_NOTIFICATION_TIMEOUT =
350 NotificationManagerService.class.getSimpleName() + ".TIMEOUT";
351 private static final int REQUEST_CODE_TIMEOUT = 1;
352 private static final String SCHEME_TIMEOUT = "timeout";
353 private static final String EXTRA_KEY = "key";
354
Adam Lesinski182f73f2013-12-05 16:48:06 -0800355 private IActivityManager mAm;
Julia Reynolds68263d12017-06-21 14:21:19 -0400356 private ActivityManager mActivityManager;
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -0500357 private IPackageManager mPackageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500358 private PackageManager mPackageManagerClient;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800359 AudioManager mAudioManager;
John Spurlockcdb57ae2015-02-11 19:04:11 -0500360 AudioManagerInternal mAudioManagerInternal;
Wei Liu97e56662016-03-04 10:52:33 -0800361 @Nullable StatusBarManagerInternal mStatusBar;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800362 Vibrator mVibrator;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700363 private WindowManagerInternal mWindowManagerInternal;
Julia Reynolds2a128742016-11-28 14:29:25 -0500364 private AlarmManager mAlarmManager;
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400365 private ICompanionDeviceManager mCompanionManager;
Julia Reynolds94187562017-10-10 13:58:49 -0400366 private AccessibilityManager mAccessibilityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -0800367 private IDeviceIdleController mDeviceIdleController;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -0700368 private IUriGrantsManager mUgm;
369 private UriGrantsManagerInternal mUgmInternal;
Julia Reynolds0c245002019-03-27 16:10:11 -0400370 private RoleObserver mRoleObserver;
371 private UserManager mUm;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 final IBinder mForegroundToken = new Binder();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400374 private WorkerHandler mHandler;
Chris Wrenf9536642014-04-17 10:01:54 -0400375 private final HandlerThread mRankingThread = new HandlerThread("ranker",
376 Process.THREAD_PRIORITY_BACKGROUND);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377
Adam Lesinski182f73f2013-12-05 16:48:06 -0800378 private Light mNotificationLight;
379 Light mAttentionLight;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800380
Daniel Sandleredbb3802012-11-13 20:49:47 -0800381 private long[] mFallbackVibrationPattern;
Chris Wren5116a822014-06-04 15:59:50 -0400382 private boolean mUseAttentionLight;
Julia Reynolds28149f62018-07-03 10:43:35 -0400383 boolean mHasLight = true;
384 boolean mLightEnabled;
Adam Lesinski182f73f2013-12-05 16:48:06 -0800385 boolean mSystemReady;
Daniel Sandleredbb3802012-11-13 20:49:47 -0800386
John Spurlockd8afe3c2014-08-01 14:04:07 -0400387 private boolean mDisableNotificationEffects;
John Spurlock32fe4c62014-10-02 12:16:02 -0400388 private int mCallState;
Chris Wren6054e612014-11-25 17:16:46 -0500389 private String mSoundNotificationKey;
390 private String mVibrateNotificationKey;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391
Julia Reynolds4703bac2018-09-12 10:39:30 -0400392 private final SparseArray<ArraySet<ComponentName>> mListenersDisablingEffects =
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400393 new SparseArray<>();
394 private List<ComponentName> mEffectsSuppressors = new ArrayList<>();
John Spurlockd8afe3c2014-08-01 14:04:07 -0400395 private int mListenerHints; // right now, all hints are global
John Spurlock83104102015-02-12 23:25:12 -0500396 private int mInterruptionFilter = NotificationListenerService.INTERRUPTION_FILTER_UNKNOWN;
John Spurlock1fa865f2014-07-21 14:56:39 -0400397
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500398 // for enabling and disabling notification pulse behavior
Julia Reynolds28149f62018-07-03 10:43:35 -0400399 boolean mScreenOn = true;
Eric Laurent7412abc2019-07-12 18:26:29 -0700400 protected boolean mInCallStateOffHook = false;
Julia Reynolds28149f62018-07-03 10:43:35 -0400401 boolean mNotificationPulseEnabled;
Mike Lockwoodc22404a2009-12-02 11:15:02 -0500402
Beverly5d463b62017-07-26 14:13:40 -0400403 private Uri mInCallNotificationUri;
404 private AudioAttributes mInCallNotificationAudioAttributes;
405 private float mInCallNotificationVolume;
luochaojiang50e5273c2018-04-16 16:55:03 +0800406 private Binder mCallNotificationToken = null;
Marta Białka39c992f2011-03-10 10:27:24 +0100407
Daniel Sandler09a247e2013-02-14 10:24:17 -0500408 // used as a mutex for access to all active notifications & listeners
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500409 final Object mNotificationLock = new Object();
Julia Reynolds0839c022017-06-15 15:24:01 -0400410 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400411 final ArrayList<NotificationRecord> mNotificationList = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400412 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400413 final ArrayMap<String, NotificationRecord> mNotificationsByKey = new ArrayMap<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400414 @GuardedBy("mNotificationLock")
Chris Wren6676dab2016-12-21 18:26:27 -0500415 final ArrayList<NotificationRecord> mEnqueuedNotifications = new ArrayList<>();
Julia Reynolds0839c022017-06-15 15:24:01 -0400416 @GuardedBy("mNotificationLock")
Julia Reynoldseae43fb2016-05-09 12:42:58 -0400417 final ArrayMap<Integer, ArrayMap<String, String>> mAutobundledSummaries = new ArrayMap<>();
Julia Reynoldseb3dca72017-07-11 10:39:58 -0400418 final ArrayList<ToastRecord> mToastQueue = new ArrayList<>();
Christoph Studer265c1052014-07-23 17:14:33 +0200419 final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420
Chris Wren6054e612014-11-25 17:16:46 -0500421 // The last key in this list owns the hardware.
422 ArrayList<String> mLights = new ArrayList<>();
svetoslavganov75986cf2009-05-14 22:28:01 -0700423
Adam Lesinski182f73f2013-12-05 16:48:06 -0800424 private AppOpsManager mAppOps;
Amith Yamasanif47e51e2015-04-17 10:02:15 -0700425 private UsageStatsManagerInternal mAppUsageStats;
Jason Parks50322ff2018-03-27 10:23:33 -0500426 private DevicePolicyManagerInternal mDpm;
Daniel Sandler4a900ac2013-01-30 14:04:10 -0500427
Griff Hazen9f637d12014-06-10 11:13:51 -0700428 private Archive mArchive;
429
John Spurlock21258a32015-05-27 18:22:55 -0400430 // Persistent storage for notification policy
Daniel Sandler0da673f2012-04-11 12:33:16 -0400431 private AtomicFile mPolicyFile;
John Spurlock21258a32015-05-27 18:22:55 -0400432
Daniel Sandler0da673f2012-04-11 12:33:16 -0400433 private static final int DB_VERSION = 1;
434
John Spurlock21258a32015-05-27 18:22:55 -0400435 private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
Daniel Sandler0da673f2012-04-11 12:33:16 -0400436 private static final String ATTR_VERSION = "version";
437
Zimuzob3b9c262018-10-31 11:54:20 +0000438 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG =
439 "allow-secure-notifications-on-lockscreen";
440 private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value";
441
Chris Wren54bbef42014-07-09 18:37:56 -0400442 private RankingHelper mRankingHelper;
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400443 private PreferencesHelper mPreferencesHelper;
Scott Greenwald9a05b312013-06-28 00:37:54 -0400444
John Spurlockb408e8e2014-04-23 21:12:45 -0400445 private final UserProfiles mUserProfiles = new UserProfiles();
John Spurlock7340fc82014-04-24 18:50:12 -0400446 private NotificationListeners mListeners;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400447 private NotificationAssistants mAssistants;
John Spurlock7340fc82014-04-24 18:50:12 -0400448 private ConditionProviders mConditionProviders;
Christoph Studer1c3f81f2014-04-16 15:05:56 +0200449 private NotificationUsageStats mUsageStats;
Selim Cinek03362962018-11-20 16:19:12 -0800450 private boolean mLockScreenAllowSecureNotifications = true;
Christoph Studer546bec82014-03-14 12:17:12 +0100451
John Spurlocke6a7d932014-03-13 12:29:00 -0400452 private static final int MY_UID = Process.myUid();
453 private static final int MY_PID = Process.myPid();
Dianne Hackborn98305522017-05-05 17:53:53 -0700454 private static final IBinder WHITELIST_TOKEN = new Binder();
Chris Wren51017d02015-12-15 15:34:46 -0500455 private RankingHandler mRankingHandler;
Chris Wrenc8673a82016-05-17 17:11:29 -0400456 private long mLastOverRateLogTime;
Chris Wren763a9bb2016-05-31 17:14:12 -0400457 private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
John Spurlocke6a7d932014-03-13 12:29:00 -0400458
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400459 private SnoozeHelper mSnoozeHelper;
Julia Reynolds8f488d32016-10-14 10:59:01 -0400460 private GroupHelper mGroupHelper;
Adora Zhang48dd614a82018-06-25 19:18:41 -0700461 private int mAutoGroupAtCount;
Julia Reynolds5f20e9f2017-01-30 08:54:53 -0500462 private boolean mIsTelevision;
Adora Zhang963328f2018-11-15 18:17:19 -0800463 private boolean mIsAutomotive;
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +0000464 private boolean mNotificationEffectsEnabledForAutomotive;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -0400465
Kenny Guy23991102018-04-05 21:18:38 +0100466 private MetricsLogger mMetricsLogger;
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500467 private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
Kenny Guy23991102018-04-05 21:18:38 +0100468
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500469 private static class Archive {
Griff Hazen9f637d12014-06-10 11:13:51 -0700470 final int mBufferSize;
471 final ArrayDeque<StatusBarNotification> mBuffer;
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500472
Griff Hazen9f637d12014-06-10 11:13:51 -0700473 public Archive(int size) {
474 mBufferSize = size;
475 mBuffer = new ArrayDeque<StatusBarNotification>(mBufferSize);
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500476 }
Jeff Sharkey0c1baf92013-04-03 13:08:52 -0700477
Daniel Sandler5e62e3a2013-04-15 20:57:02 -0400478 public String toString() {
479 final StringBuilder sb = new StringBuilder();
480 final int N = mBuffer.size();
481 sb.append("Archive (");
482 sb.append(N);
483 sb.append(" notification");
484 sb.append((N==1)?")":"s)");
485 return sb.toString();
486 }
487
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500488 public void record(StatusBarNotification nr) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700489 if (mBuffer.size() == mBufferSize) {
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500490 mBuffer.removeFirst();
491 }
Daniel Sandler26b81d52013-05-20 20:56:43 -0400492
493 // We don't want to store the heavy bits of the notification in the archive,
494 // but other clients in the system process might be using the object, so we
495 // store a (lightened) copy.
496 mBuffer.addLast(nr.cloneLight());
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500497 }
498
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500499 public Iterator<StatusBarNotification> descendingIterator() {
500 return mBuffer.descendingIterator();
501 }
Daniel Sandler78d0d252013-02-12 08:14:52 -0500502
503 public StatusBarNotification[] getArray(int count) {
Griff Hazen9f637d12014-06-10 11:13:51 -0700504 if (count == 0) count = mBufferSize;
Daniel Sandler78d0d252013-02-12 08:14:52 -0500505 final StatusBarNotification[] a
506 = new StatusBarNotification[Math.min(count, mBuffer.size())];
507 Iterator<StatusBarNotification> iter = descendingIterator();
508 int i=0;
509 while (iter.hasNext() && i < count) {
510 a[i++] = iter.next();
511 }
512 return a;
513 }
514
Daniel Sandlerfde19b12013-01-17 00:21:05 -0500515 }
516
Julia Reynolds88a879f2017-07-26 17:06:46 -0400517 protected void readDefaultApprovedServices(int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400518 String defaultListenerAccess = getContext().getResources().getString(
519 com.android.internal.R.string.config_defaultListenerAccessPackages);
520 if (defaultListenerAccess != null) {
521 for (String whitelisted :
522 defaultListenerAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
523 // Gather all notification listener components for candidate pkgs.
524 Set<ComponentName> approvedListeners =
525 mListeners.queryPackageForServices(whitelisted,
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -0400526 MATCH_DIRECT_BOOT_AWARE
527 | MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400528 for (ComponentName cn : approvedListeners) {
529 try {
530 getBinderService().setNotificationListenerAccessGrantedForUser(cn,
531 userId, true);
532 } catch (RemoteException e) {
533 e.printStackTrace();
534 }
535 }
536 }
537 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500538
Julia Reynoldsb852e562017-06-06 16:14:18 -0400539 String defaultDndAccess = getContext().getResources().getString(
540 com.android.internal.R.string.config_defaultDndAccessPackages);
Edward Savage-Jones36a89422018-07-19 12:23:58 +0200541 if (defaultDndAccess != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400542 for (String whitelisted :
543 defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR)) {
544 try {
545 getBinderService().setNotificationPolicyAccessGranted(whitelisted, true);
546 } catch (RemoteException e) {
547 e.printStackTrace();
548 }
549 }
550 }
Julia Reynolds7380d872018-01-12 10:28:26 -0500551
Tony Mak9a3c1f12019-03-04 16:04:42 +0000552 setDefaultAssistantForUser(userId);
Julia Reynolds7380d872018-01-12 10:28:26 -0500553 }
554
Tony Mak9a3c1f12019-03-04 16:04:42 +0000555 protected void setDefaultAssistantForUser(int userId) {
556 List<ComponentName> validAssistants = new ArrayList<>(
557 mAssistants.queryPackageForServices(
558 null, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId));
559
560 List<String> candidateStrs = new ArrayList<>();
561 candidateStrs.add(DeviceConfig.getProperty(
562 DeviceConfig.NAMESPACE_SYSTEMUI,
563 SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE));
564 candidateStrs.add(getContext().getResources().getString(
565 com.android.internal.R.string.config_defaultAssistantAccessComponent));
566
567 for (String candidateStr : candidateStrs) {
568 if (TextUtils.isEmpty(candidateStr)) {
569 continue;
570 }
571 ComponentName candidate = ComponentName.unflattenFromString(candidateStr);
572 if (candidate != null && validAssistants.contains(candidate)) {
573 setNotificationAssistantAccessGrantedForUserInternal(candidate, userId, true);
574 Slog.d(TAG, String.format("Set default NAS to be %s in %d", candidateStr, userId));
575 return;
576 } else {
577 Slog.w(TAG, "Invalid default NAS config is found: " + candidateStr);
Julia Reynolds7380d872018-01-12 10:28:26 -0500578 }
579 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400580 }
581
Annie Meng8b646fd2019-02-01 18:46:42 +0000582 void readPolicyXml(InputStream stream, boolean forRestore, int userId)
John Spurlock35ef0a62015-05-28 11:24:10 -0400583 throws XmlPullParserException, NumberFormatException, IOException {
584 final XmlPullParser parser = Xml.newPullParser();
585 parser.setInput(stream, StandardCharsets.UTF_8.name());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400586 XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
587 boolean migratedManagedServices = false;
Julia Reynolds0c245002019-03-27 16:10:11 -0400588 boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400589 int outerDepth = parser.getDepth();
590 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
591 if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000592 mZenModeHelper.readXml(parser, forRestore, userId);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -0400593 } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
Annie Meng8b646fd2019-02-01 18:46:42 +0000594 mPreferencesHelper.readXml(parser, forRestore, userId);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400595 }
Kristian Monsen30f59b22018-04-09 10:27:16 +0200596 if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000597 if (ineligibleForManagedServices) {
598 continue;
599 }
600 mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
Kristian Monsen30f59b22018-04-09 10:27:16 +0200601 migratedManagedServices = true;
602 } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000603 if (ineligibleForManagedServices) {
604 continue;
605 }
606 mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
Kristian Monsen30f59b22018-04-09 10:27:16 +0200607 migratedManagedServices = true;
608 } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000609 if (ineligibleForManagedServices) {
610 continue;
611 }
612 mConditionProviders.readXml(
613 parser, mAllowedManagedServicePackages, forRestore, userId);
Kristian Monsen30f59b22018-04-09 10:27:16 +0200614 migratedManagedServices = true;
Julia Reynolds68263d12017-06-21 14:21:19 -0400615 }
Zimuzob3b9c262018-10-31 11:54:20 +0000616 if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000617 if (forRestore && userId != UserHandle.USER_SYSTEM) {
618 continue;
619 }
Zimuzob3b9c262018-10-31 11:54:20 +0000620 mLockScreenAllowSecureNotifications =
621 safeBoolean(parser.getAttributeValue(null,
622 LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
623 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400624 }
625
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400626 if (!migratedManagedServices) {
627 mListeners.migrateToXml();
628 mAssistants.migrateToXml();
629 mConditionProviders.migrateToXml();
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500630 handleSavePolicyFile();
John Spurlock35ef0a62015-05-28 11:24:10 -0400631 }
Tony Mak9a3c1f12019-03-04 16:04:42 +0000632
633 mAssistants.resetDefaultAssistantsIfNecessary();
John Spurlock35ef0a62015-05-28 11:24:10 -0400634 }
635
Julia Reynolds0c245002019-03-27 16:10:11 -0400636 @VisibleForTesting
637 protected void loadPolicyFile() {
John Spurlock21258a32015-05-27 18:22:55 -0400638 if (DBG) Slog.d(TAG, "loadPolicyFile");
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500639 synchronized (mPolicyFile) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400640 InputStream infile = null;
John Spurlock056c5192014-04-20 21:52:01 -0400641 try {
642 infile = mPolicyFile.openRead();
Annie Meng8b646fd2019-02-01 18:46:42 +0000643 readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
John Spurlock056c5192014-04-20 21:52:01 -0400644 } catch (FileNotFoundException e) {
645 // No data yet
Julia Reynoldsb852e562017-06-06 16:14:18 -0400646 // Load default managed services approvals
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400647 readDefaultApprovedServices(USER_SYSTEM);
John Spurlock056c5192014-04-20 21:52:01 -0400648 } catch (IOException e) {
649 Log.wtf(TAG, "Unable to read notification policy", e);
650 } catch (NumberFormatException e) {
651 Log.wtf(TAG, "Unable to parse notification policy", e);
652 } catch (XmlPullParserException e) {
653 Log.wtf(TAG, "Unable to parse notification policy", e);
654 } finally {
655 IoUtils.closeQuietly(infile);
656 }
657 }
658 }
659
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500660 @VisibleForTesting
661 protected void handleSavePolicyFile() {
662 IoThread.getHandler().post(() -> {
663 if (DBG) Slog.d(TAG, "handleSavePolicyFile");
664 synchronized (mPolicyFile) {
665 final FileOutputStream stream;
666 try {
667 stream = mPolicyFile.startWrite();
668 } catch (IOException e) {
669 Slog.w(TAG, "Failed to save policy file", e);
670 return;
671 }
John Spurlock056c5192014-04-20 21:52:01 -0400672
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500673 try {
Annie Meng8b646fd2019-02-01 18:46:42 +0000674 writePolicyXml(stream, false /*forBackup*/, UserHandle.USER_ALL);
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500675 mPolicyFile.finishWrite(stream);
676 } catch (IOException e) {
677 Slog.w(TAG, "Failed to save policy file, restoring backup", e);
678 mPolicyFile.failWrite(stream);
679 }
Daniel Sandler0da673f2012-04-11 12:33:16 -0400680 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -0500681 BackupManager.dataChanged(getContext().getPackageName());
682 });
John Spurlock35ef0a62015-05-28 11:24:10 -0400683 }
684
Annie Meng8b646fd2019-02-01 18:46:42 +0000685 private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
686 throws IOException {
John Spurlock35ef0a62015-05-28 11:24:10 -0400687 final XmlSerializer out = new FastXmlSerializer();
688 out.setOutput(stream, StandardCharsets.UTF_8.name());
689 out.startDocument(null, true);
690 out.startTag(null, TAG_NOTIFICATION_POLICY);
691 out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
Annie Meng8b646fd2019-02-01 18:46:42 +0000692 mZenModeHelper.writeXml(out, forBackup, null, userId);
693 mPreferencesHelper.writeXml(out, forBackup, userId);
694 mListeners.writeXml(out, forBackup, userId);
695 mAssistants.writeXml(out, forBackup, userId);
696 mConditionProviders.writeXml(out, forBackup, userId);
697 if (!forBackup || userId == UserHandle.USER_SYSTEM) {
698 writeSecureNotificationsPolicy(out);
699 }
John Spurlock35ef0a62015-05-28 11:24:10 -0400700 out.endTag(null, TAG_NOTIFICATION_POLICY);
701 out.endDocument();
Daniel Sandler0da673f2012-04-11 12:33:16 -0400702 }
703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 private static final class ToastRecord
705 {
706 final int pid;
707 final String pkg;
Beverly Taia7ed0ab2018-06-11 14:50:36 +0000708 final ITransientNotification callback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 int duration;
Jeff Chang48ecef42018-08-09 16:31:59 +0800710 int displayId;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700711 Binder token;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700713 ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
Jeff Chang48ecef42018-08-09 16:31:59 +0800714 Binder token, int displayId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 this.pid = pid;
716 this.pkg = pkg;
717 this.callback = callback;
718 this.duration = duration;
Svetoslav Ganovaa076532016-08-01 19:16:43 -0700719 this.token = token;
Jeff Chang48ecef42018-08-09 16:31:59 +0800720 this.displayId = displayId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 }
722
723 void update(int duration) {
724 this.duration = duration;
725 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800726
John Spurlock25e2d242014-06-27 13:58:23 -0400727 void dump(PrintWriter pw, String prefix, DumpFilter filter) {
728 if (filter != null && !filter.matches(pkg)) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 pw.println(prefix + this);
730 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 @Override
733 public final String toString()
734 {
735 return "ToastRecord{"
736 + Integer.toHexString(System.identityHashCode(this))
737 + " pkg=" + pkg
738 + " callback=" + callback
739 + " duration=" + duration;
740 }
741 }
742
Beverly40239d92017-07-07 10:20:41 -0400743 @VisibleForTesting
744 final NotificationDelegate mNotificationDelegate = new NotificationDelegate() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745
Adam Lesinski182f73f2013-12-05 16:48:06 -0800746 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 public void onSetDisabled(int status) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500748 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -0400749 mDisableNotificationEffects =
750 (status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
John Spurlock32fe4c62014-10-02 12:16:02 -0400751 if (disableNotificationEffects(null) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 // cancel whatever's going on
753 long identity = Binder.clearCallingIdentity();
754 try {
Adam Lesinski182f73f2013-12-05 16:48:06 -0800755 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700756 if (player != null) {
757 player.stopAsync();
758 }
759 } catch (RemoteException e) {
760 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 Binder.restoreCallingIdentity(identity);
762 }
763
764 identity = Binder.clearCallingIdentity();
765 try {
766 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -0700767 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 Binder.restoreCallingIdentity(identity);
769 }
770 }
771 }
772 }
773
Adam Lesinski182f73f2013-12-05 16:48:06 -0800774 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400775 public void onClearAll(int callingUid, int callingPid, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500776 synchronized (mNotificationLock) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400777 cancelAllLocked(callingUid, callingPid, userId, REASON_CANCEL_ALL, null,
Kenny Guya263e4e2014-03-03 18:24:03 +0000778 /*includeCurrentProfiles*/ true);
Adam Lesinskie8240262014-03-26 16:01:00 -0700779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 }
781
Adam Lesinski182f73f2013-12-05 16:48:06 -0800782 @Override
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400783 public void onNotificationClick(int callingUid, int callingPid, String key,
784 NotificationVisibility nv) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800785 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500786 synchronized (mNotificationLock) {
Christoph Studer03b87a22014-04-30 17:33:27 +0200787 NotificationRecord r = mNotificationsByKey.get(key);
788 if (r == null) {
Tony Mak180a9c42019-03-08 13:33:08 +0000789 Slog.w(TAG, "No notification with key: " + key);
Christoph Studer03b87a22014-04-30 17:33:27 +0200790 return;
791 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400792 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400793 MetricsLogger.action(r.getItemLogMaker()
Dieter Hsud39f0d52018-04-14 02:08:30 +0800794 .setType(MetricsEvent.TYPE_ACTION)
795 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
796 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count));
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400797 EventLogTags.writeNotificationClicked(key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800798 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
799 nv.rank, nv.count);
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400800
Christoph Studer03b87a22014-04-30 17:33:27 +0200801 StatusBarNotification sbn = r.sbn;
802 cancelNotification(callingUid, callingPid, sbn.getPackageName(), sbn.getTag(),
803 sbn.getId(), Notification.FLAG_AUTO_CANCEL,
Julia Reynoldse5c60452018-04-30 14:41:36 -0400804 FLAG_FOREGROUND_SERVICE, false, r.getUserId(),
Dieter Hsud39f0d52018-04-14 02:08:30 +0800805 REASON_CLICK, nv.rank, nv.count, null);
806 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800807 reportUserInteraction(r);
Christoph Studer03b87a22014-04-30 17:33:27 +0200808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
810
Adam Lesinski182f73f2013-12-05 16:48:06 -0800811 @Override
Christoph Studer4da84cd2014-10-21 17:24:20 +0200812 public void onNotificationActionClick(int callingUid, int callingPid, String key,
Tony Mak7d4b3a52018-11-27 17:29:36 +0000813 int actionIndex, Notification.Action action, NotificationVisibility nv,
814 boolean generatedByAssistant) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800815 exitIdle();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500816 synchronized (mNotificationLock) {
Christoph Studer4da84cd2014-10-21 17:24:20 +0200817 NotificationRecord r = mNotificationsByKey.get(key);
818 if (r == null) {
Tony Mak180a9c42019-03-08 13:33:08 +0000819 Slog.w(TAG, "No notification with key: " + key);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200820 return;
821 }
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400822 final long now = System.currentTimeMillis();
Chris Wren9eb5e102017-01-26 13:15:06 -0500823 MetricsLogger.action(r.getLogMaker(now)
824 .setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION)
825 .setType(MetricsEvent.TYPE_ACTION)
Dieter Hsud39f0d52018-04-14 02:08:30 +0800826 .setSubtype(actionIndex)
827 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, nv.rank)
Gustav Senntond25a64d2018-12-07 10:58:39 +0000828 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, nv.count)
829 .addTaggedData(MetricsEvent.NOTIFICATION_ACTION_IS_SMART,
Gustav Sennton005d7a02019-01-04 13:41:32 +0000830 action.isContextual() ? 1 : 0)
Gustav Senntond25a64d2018-12-07 10:58:39 +0000831 .addTaggedData(
832 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Gustav Sennton72991962019-01-28 21:09:54 +0000833 generatedByAssistant ? 1 : 0)
834 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
835 nv.location.toMetricsEventEnum()));
836
Chris Wrene6ddb8a2015-05-27 15:21:00 -0400837 EventLogTags.writeNotificationActionClicked(key, actionIndex,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800838 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
839 nv.rank, nv.count);
840 nv.recycle();
Amith Yamasani7ec89412018-02-07 08:48:49 -0800841 reportUserInteraction(r);
Tony Mak7d4b3a52018-11-27 17:29:36 +0000842 mAssistants.notifyAssistantActionClicked(
843 r.sbn, actionIndex, action, generatedByAssistant);
Christoph Studer4da84cd2014-10-21 17:24:20 +0200844 }
845 }
846
847 @Override
John Spurlocke6a7d932014-03-13 12:29:00 -0400848 public void onNotificationClear(int callingUid, int callingPid,
Julia Reynolds503ed942017-10-04 16:04:56 -0400849 String pkg, String tag, int id, int userId, String key,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800850 @NotificationStats.DismissalSurface int dismissalSurface,
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400851 @NotificationStats.DismissalSentiment int dismissalSentiment,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800852 NotificationVisibility nv) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400853 synchronized (mNotificationLock) {
854 NotificationRecord r = mNotificationsByKey.get(key);
855 if (r != null) {
856 r.recordDismissalSurface(dismissalSurface);
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400857 r.recordDismissalSentiment(dismissalSentiment);
Julia Reynolds503ed942017-10-04 16:04:56 -0400858 }
859 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400860 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Mady Mellor49b1bf12019-03-29 12:00:02 -0700861 FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE,
Dieter Hsud39f0d52018-04-14 02:08:30 +0800862 true, userId, REASON_CANCEL, nv.rank, nv.count,null);
863 nv.recycle();
Daniel Sandler0f0b11c2010-08-04 15:54:58 -0400864 }
865
Adam Lesinski182f73f2013-12-05 16:48:06 -0800866 @Override
Chris Wrenb659c4f2015-06-25 17:12:27 -0400867 public void onPanelRevealed(boolean clearEffects, int items) {
Chris Wren9eb5e102017-01-26 13:15:06 -0500868 MetricsLogger.visible(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Chris Wren621933f2017-06-14 15:59:03 -0400869 MetricsLogger.histogram(getContext(), "note_load", items);
Chris Wrenb659c4f2015-06-25 17:12:27 -0400870 EventLogTags.writeNotificationPanelRevealed(items);
Christoph Studer1f32c652014-11-26 15:32:20 +0100871 if (clearEffects) {
872 clearEffects();
873 }
874 }
875
876 @Override
877 public void onPanelHidden() {
Chris Wren9eb5e102017-01-26 13:15:06 -0500878 MetricsLogger.hidden(getContext(), MetricsEvent.NOTIFICATION_PANEL);
Christoph Studer1f32c652014-11-26 15:32:20 +0100879 EventLogTags.writeNotificationPanelHidden();
880 }
881
882 @Override
883 public void clearEffects() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500884 synchronized (mNotificationLock) {
Christoph Studer1f32c652014-11-26 15:32:20 +0100885 if (DBG) Slog.d(TAG, "clearEffects");
Chris Wren93bb8b82016-03-29 14:35:05 -0400886 clearSoundLocked();
887 clearVibrateLocked();
888 clearLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 }
890 }
Joe Onorato005847b2010-06-04 16:08:02 -0400891
Adam Lesinski182f73f2013-12-05 16:48:06 -0800892 @Override
Julia Reynoldsfd4099d2018-08-21 11:06:06 -0400893 public void onNotificationError(int callingUid, int callingPid, String pkg, String tag,
894 int id, int uid, int initialPid, String message, int userId) {
Da Xing70876ce2018-11-18 20:10:17 +0800895 final boolean fgService;
896 synchronized (mNotificationLock) {
897 NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
898 fgService = r != null && (r.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0;
899 }
John Spurlocke6a7d932014-03-13 12:29:00 -0400900 cancelNotification(callingUid, callingPid, pkg, tag, id, 0, 0, false, userId,
Julia Reynoldsf619bc52017-03-17 08:32:23 -0400901 REASON_ERROR, null);
Da Xing70876ce2018-11-18 20:10:17 +0800902 if (fgService) {
903 // Still crash for foreground services, preventing the not-crash behaviour abused
904 // by apps to give us a garbage notification and silently start a fg service.
905 Binder.withCleanCallingIdentity(
906 () -> mAm.crashApplication(uid, initialPid, pkg, -1,
907 "Bad notification(tag=" + tag + ", id=" + id + ") posted from package "
908 + pkg + ", crashing app(uid=" + uid + ", pid=" + initialPid + "): "
909 + message));
910 }
Joe Onorato005847b2010-06-04 16:08:02 -0400911 }
John Spurlocke677d712014-02-13 12:52:19 -0500912
913 @Override
Chris Wrend1dbc922015-06-19 17:51:16 -0400914 public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
915 NotificationVisibility[] noLongerVisibleKeys) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500916 synchronized (mNotificationLock) {
Chris Wrend1dbc922015-06-19 17:51:16 -0400917 for (NotificationVisibility nv : newlyVisibleKeys) {
918 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200919 if (r == null) continue;
Amith Yamasani803eab692017-11-09 17:47:04 -0800920 if (!r.isSeen()) {
921 // Report to usage stats that notification was made visible
922 if (DBG) Slog.d(TAG, "Marking notification as visible " + nv.key);
923 reportSeen(r);
924 }
Dieter Hsud39f0d52018-04-14 02:08:30 +0800925 r.setVisibility(true, nv.rank, nv.count);
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000926 boolean isHun = (nv.location
927 == NotificationVisibility.NotificationLocation.LOCATION_FIRST_HEADS_UP);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000928 // hasBeenVisiblyExpanded must be called after updating the expansion state of
929 // the NotificationRecord to ensure the expansion state is up-to-date.
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000930 if (isHun || r.hasBeenVisiblyExpanded()) {
931 logSmartSuggestionsVisible(r, nv.location.toMetricsEventEnum());
Gustav Sennton44dc5882018-12-13 14:38:50 +0000932 }
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -0400933 maybeRecordInterruptionLocked(r);
Chris Wrend1dbc922015-06-19 17:51:16 -0400934 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200935 }
936 // Note that we might receive this event after notifications
937 // have already left the system, e.g. after dismissing from the
938 // shade. Hence not finding notifications in
939 // mNotificationsByKey is not an exceptional condition.
Chris Wrend1dbc922015-06-19 17:51:16 -0400940 for (NotificationVisibility nv : noLongerVisibleKeys) {
941 NotificationRecord r = mNotificationsByKey.get(nv.key);
Christoph Studerffeb0c32014-05-07 22:23:56 +0200942 if (r == null) continue;
Dieter Hsud39f0d52018-04-14 02:08:30 +0800943 r.setVisibility(false, nv.rank, nv.count);
Chris Wrend1dbc922015-06-19 17:51:16 -0400944 nv.recycle();
Christoph Studerffeb0c32014-05-07 22:23:56 +0200945 }
946 }
Christoph Studer92b389d2014-04-01 18:44:40 +0200947 }
Chris Wren78403d72014-07-28 10:23:24 +0100948
949 @Override
950 public void onNotificationExpansionChanged(String key,
Gustav Senntona8e38aa2019-01-22 14:55:39 +0000951 boolean userAction, boolean expanded, int notificationLocation) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -0500952 synchronized (mNotificationLock) {
Chris Wren78403d72014-07-28 10:23:24 +0100953 NotificationRecord r = mNotificationsByKey.get(key);
954 if (r != null) {
955 r.stats.onExpansionChanged(userAction, expanded);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000956 // hasBeenVisiblyExpanded must be called after updating the expansion state of
957 // the NotificationRecord to ensure the expansion state is up-to-date.
958 if (r.hasBeenVisiblyExpanded()) {
Gustav Senntonc7d0d322019-01-07 15:36:41 +0000959 logSmartSuggestionsVisible(r, notificationLocation);
Gustav Sennton44dc5882018-12-13 14:38:50 +0000960 }
Chris Wrenf7342712017-09-14 10:55:55 -0400961 if (userAction) {
Julia Reynolds3dfdde02018-10-08 09:17:56 -0400962 MetricsLogger.action(r.getItemLogMaker()
Chris Wrenf7342712017-09-14 10:55:55 -0400963 .setType(expanded ? MetricsEvent.TYPE_DETAIL
964 : MetricsEvent.TYPE_COLLAPSE));
Chris Wren377ac6d2017-09-12 14:15:23 -0400965 }
Julia Reynolds84dc96b2017-11-14 09:51:01 -0500966 if (expanded && userAction) {
Julia Reynolds503ed942017-10-04 16:04:56 -0400967 r.recordExpanded();
Esteban Talavera917a71d2018-11-13 07:55:08 +0000968 reportUserInteraction(r);
Julia Reynolds503ed942017-10-04 16:04:56 -0400969 }
Tony Makeda84a72018-11-19 17:01:32 +0000970 mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded);
Chris Wren78403d72014-07-28 10:23:24 +0100971 }
972 }
973 }
Julia Reynolds503ed942017-10-04 16:04:56 -0400974
975 @Override
976 public void onNotificationDirectReplied(String key) {
Amith Yamasani396a10c2018-01-19 10:58:07 -0800977 exitIdle();
Julia Reynolds503ed942017-10-04 16:04:56 -0400978 synchronized (mNotificationLock) {
979 NotificationRecord r = mNotificationsByKey.get(key);
980 if (r != null) {
981 r.recordDirectReplied();
Esteban Talaveraf9c53b62018-11-14 18:20:29 +0000982 mMetricsLogger.write(r.getLogMaker()
983 .setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
984 .setType(MetricsEvent.TYPE_ACTION));
Amith Yamasani7ec89412018-02-07 08:48:49 -0800985 reportUserInteraction(r);
Tony Makeda84a72018-11-19 17:01:32 +0000986 mAssistants.notifyAssistantNotificationDirectReplyLocked(r.sbn);
Julia Reynolds503ed942017-10-04 16:04:56 -0400987 }
988 }
989 }
990
991 @Override
Gustav Senntond25a64d2018-12-07 10:58:39 +0000992 public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
Milo Sredkov13d88112019-02-01 12:23:24 +0000993 int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
Kenny Guy23991102018-04-05 21:18:38 +0100994 synchronized (mNotificationLock) {
995 NotificationRecord r = mNotificationsByKey.get(key);
996 if (r != null) {
Gustav Senntond25a64d2018-12-07 10:58:39 +0000997 r.setNumSmartRepliesAdded(smartReplyCount);
998 r.setNumSmartActionsAdded(smartActionCount);
999 r.setSuggestionsGeneratedByAssistant(generatedByAssistant);
Milo Sredkov13d88112019-02-01 12:23:24 +00001000 r.setEditChoicesBeforeSending(editBeforeSending);
Kenny Guy23991102018-04-05 21:18:38 +01001001 }
1002 }
1003 }
1004
1005 @Override
Tony Mak29996702018-11-26 16:23:34 +00001006 public void onNotificationSmartReplySent(String key, int replyIndex, CharSequence reply,
Milo Sredkov13d88112019-02-01 12:23:24 +00001007 int notificationLocation, boolean modifiedBeforeSending) {
Gustav Senntond25a64d2018-12-07 10:58:39 +00001008
Kenny Guy23991102018-04-05 21:18:38 +01001009 synchronized (mNotificationLock) {
1010 NotificationRecord r = mNotificationsByKey.get(key);
1011 if (r != null) {
1012 LogMaker logMaker = r.getLogMaker()
1013 .setCategory(MetricsEvent.SMART_REPLY_ACTION)
Gustav Sennton13edb492019-01-28 21:40:04 +00001014 .setSubtype(replyIndex)
1015 .addTaggedData(
1016 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Milo Sredkov13d88112019-02-01 12:23:24 +00001017 r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
Gustav Sennton13edb492019-01-28 21:40:04 +00001018 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION,
Milo Sredkov13d88112019-02-01 12:23:24 +00001019 notificationLocation)
1020 .addTaggedData(
1021 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1022 r.getEditChoicesBeforeSending() ? 1 : 0)
1023 .addTaggedData(
1024 MetricsEvent.NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING,
1025 modifiedBeforeSending ? 1 : 0);
Kenny Guy23991102018-04-05 21:18:38 +01001026 mMetricsLogger.write(logMaker);
1027 // Treat clicking on a smart reply as a user interaction.
1028 reportUserInteraction(r);
Tony Mak29996702018-11-26 16:23:34 +00001029 mAssistants.notifyAssistantSuggestedReplySent(
Milo Sredkov13d88112019-02-01 12:23:24 +00001030 r.sbn, reply, r.getSuggestionsGeneratedByAssistant());
Kenny Guy23991102018-04-05 21:18:38 +01001031 }
1032 }
1033 }
1034
1035 @Override
Julia Reynolds503ed942017-10-04 16:04:56 -04001036 public void onNotificationSettingsViewed(String key) {
1037 synchronized (mNotificationLock) {
1038 NotificationRecord r = mNotificationsByKey.get(key);
1039 if (r != null) {
1040 r.recordViewedSettings();
1041 }
1042 }
1043 }
Mady Mellora54e9fa2019-04-18 13:26:18 -07001044
1045 @Override
1046 public void onNotificationBubbleChanged(String key, boolean isBubble) {
1047 synchronized (mNotificationLock) {
1048 NotificationRecord r = mNotificationsByKey.get(key);
1049 if (r != null) {
1050 final StatusBarNotification n = r.sbn;
1051 final int callingUid = n.getUid();
1052 final String pkg = n.getPackageName();
1053 if (isBubble && isNotificationAppropriateToBubble(r, pkg, callingUid,
1054 null /* oldEntry */)) {
1055 r.getNotification().flags |= FLAG_BUBBLE;
1056 } else {
1057 r.getNotification().flags &= ~FLAG_BUBBLE;
1058 }
1059 }
1060 }
1061 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 };
1063
Gustav Sennton44dc5882018-12-13 14:38:50 +00001064 @VisibleForTesting
Gustav Senntonc7d0d322019-01-07 15:36:41 +00001065 void logSmartSuggestionsVisible(NotificationRecord r, int notificationLocation) {
Gustav Sennton44dc5882018-12-13 14:38:50 +00001066 // If the newly visible notification has smart suggestions
1067 // then log that the user has seen them.
1068 if ((r.getNumSmartRepliesAdded() > 0 || r.getNumSmartActionsAdded() > 0)
1069 && !r.hasSeenSmartReplies()) {
1070 r.setSeenSmartReplies(true);
1071 LogMaker logMaker = r.getLogMaker()
1072 .setCategory(MetricsEvent.SMART_REPLY_VISIBLE)
1073 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_REPLY_COUNT,
1074 r.getNumSmartRepliesAdded())
1075 .addTaggedData(MetricsEvent.NOTIFICATION_SMART_ACTION_COUNT,
1076 r.getNumSmartActionsAdded())
1077 .addTaggedData(
1078 MetricsEvent.NOTIFICATION_SMART_SUGGESTION_ASSISTANT_GENERATED,
Gustav Senntonc7d0d322019-01-07 15:36:41 +00001079 r.getSuggestionsGeneratedByAssistant() ? 1 : 0)
1080 // The fields in the NotificationVisibility.NotificationLocation enum map
1081 // directly to the fields in the MetricsEvent.NotificationLocation enum.
Milo Sredkov13d88112019-02-01 12:23:24 +00001082 .addTaggedData(MetricsEvent.NOTIFICATION_LOCATION, notificationLocation)
1083 .addTaggedData(
1084 MetricsEvent.NOTIFICATION_SMART_REPLY_EDIT_BEFORE_SENDING,
1085 r.getEditChoicesBeforeSending() ? 1 : 0);
Gustav Sennton44dc5882018-12-13 14:38:50 +00001086 mMetricsLogger.write(logMaker);
1087 }
1088 }
1089
Julia Reynolds88860ce2017-06-01 16:55:49 -04001090 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001091 private void clearSoundLocked() {
1092 mSoundNotificationKey = null;
1093 long identity = Binder.clearCallingIdentity();
1094 try {
1095 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
1096 if (player != null) {
1097 player.stopAsync();
1098 }
1099 } catch (RemoteException e) {
1100 } finally {
1101 Binder.restoreCallingIdentity(identity);
1102 }
1103 }
1104
Julia Reynolds88860ce2017-06-01 16:55:49 -04001105 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001106 private void clearVibrateLocked() {
1107 mVibrateNotificationKey = null;
1108 long identity = Binder.clearCallingIdentity();
1109 try {
1110 mVibrator.cancel();
1111 } finally {
1112 Binder.restoreCallingIdentity(identity);
1113 }
1114 }
1115
Julia Reynolds88860ce2017-06-01 16:55:49 -04001116 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04001117 private void clearLightsLocked() {
1118 // light
1119 mLights.clear();
1120 updateLightsLocked();
1121 }
1122
Beverlyd4f96492017-08-02 13:36:11 -04001123 protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
1124 @Override
1125 public void onReceive(Context context, Intent intent) {
1126 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
Beverly70dcd002018-03-29 17:09:16 -04001127 // update system notification channels
1128 SystemNotificationChannels.createAll(context);
Beverlyd4f96492017-08-02 13:36:11 -04001129 mZenModeHelper.updateDefaultZenRules();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001130 mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
Beverlyd4f96492017-08-02 13:36:11 -04001131 }
1132 }
1133 };
1134
Julia Reynoldsb852e562017-06-06 16:14:18 -04001135 private final BroadcastReceiver mRestoreReceiver = new BroadcastReceiver() {
1136 @Override
1137 public void onReceive(Context context, Intent intent) {
1138 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
1139 try {
1140 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
1141 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
Michal Karpinski6135a262017-08-11 10:45:58 +01001142 int restoredFromSdkInt = intent.getIntExtra(
1143 Intent.EXTRA_SETTING_RESTORED_FROM_SDK_INT, 0);
Julia Reynoldsfa206a42017-08-14 13:22:23 -04001144 mListeners.onSettingRestored(
1145 element, newValue, restoredFromSdkInt, getSendingUserId());
1146 mConditionProviders.onSettingRestored(
1147 element, newValue, restoredFromSdkInt, getSendingUserId());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001148 } catch (Exception e) {
1149 Slog.wtf(TAG, "Cannot restore managed services from settings", e);
1150 }
1151 }
1152 }
1153 };
1154
Julia Reynolds2a128742016-11-28 14:29:25 -05001155 private final BroadcastReceiver mNotificationTimeoutReceiver = new BroadcastReceiver() {
1156 @Override
1157 public void onReceive(Context context, Intent intent) {
1158 String action = intent.getAction();
1159 if (action == null) {
1160 return;
1161 }
1162 if (ACTION_NOTIFICATION_TIMEOUT.equals(action)) {
1163 final NotificationRecord record;
1164 synchronized (mNotificationLock) {
1165 record = findNotificationByKeyLocked(intent.getStringExtra(EXTRA_KEY));
1166 }
1167 if (record != null) {
1168 cancelNotification(record.sbn.getUid(), record.sbn.getInitialPid(),
1169 record.sbn.getPackageName(), record.sbn.getTag(),
1170 record.sbn.getId(), 0,
Julia Reynoldse5c60452018-04-30 14:41:36 -04001171 FLAG_FOREGROUND_SERVICE, true, record.getUserId(),
Julia Reynolds2a128742016-11-28 14:29:25 -05001172 REASON_TIMEOUT, null);
1173 }
1174 }
1175 }
1176 };
1177
Kenny Guy70058402014-10-28 20:45:06 +00001178 private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 @Override
1180 public void onReceive(Context context, Intent intent) {
1181 String action = intent.getAction();
Dianne Hackborn29cd7f12015-01-08 10:37:05 -08001182 if (action == null) {
1183 return;
1184 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001186 boolean queryRestart = false;
Chris Wrenae9bb572013-05-15 14:50:28 -04001187 boolean queryRemove = false;
Daniel Sandler26ece572012-06-01 15:38:46 -04001188 boolean packageChanged = false;
John Spurlock79f78922013-05-16 09:10:05 -04001189 boolean cancelNotifications = true;
Beverly5a20a5e2018-03-06 15:02:44 -05001190 boolean hideNotifications = false;
1191 boolean unhideNotifications = false;
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001192 int reason = REASON_PACKAGE_CHANGED;
Chris Wrenf9536642014-04-17 10:01:54 -04001193
Chris Wren3da73022013-05-10 14:41:21 -04001194 if (action.equals(Intent.ACTION_PACKAGE_ADDED)
Chris Wrenae9bb572013-05-15 14:50:28 -04001195 || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001196 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Daniel Sandler26ece572012-06-01 15:38:46 -04001197 || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001198 || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001199 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)
Beverly5a20a5e2018-03-06 15:02:44 -05001200 || action.equals(Intent.ACTION_PACKAGES_SUSPENDED)
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001201 || action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)
1202 || action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
Kenny Guy70058402014-10-28 20:45:06 +00001203 int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
1204 UserHandle.USER_ALL);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001205 String pkgList[] = null;
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001206 int uidList[] = null;
Julia Reynolds6434eb22016-08-08 17:19:26 -04001207 boolean removingPackage = queryRemove &&
1208 !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
1209 if (DBG) Slog.i(TAG, "action=" + action + " removing=" + removingPackage);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001210 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001211 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001212 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001213 } else if (action.equals(Intent.ACTION_PACKAGES_SUSPENDED)) {
1214 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001215 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001216 cancelNotifications = false;
1217 hideNotifications = true;
1218 } else if (action.equals(Intent.ACTION_PACKAGES_UNSUSPENDED)) {
1219 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
Julia Reynolds4bc42b92018-08-14 11:27:35 -04001220 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
Beverly5a20a5e2018-03-06 15:02:44 -05001221 cancelNotifications = false;
1222 unhideNotifications = true;
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001223 } else if (action.equals(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)) {
1224 final int distractionRestrictions =
1225 intent.getIntExtra(Intent.EXTRA_DISTRACTION_RESTRICTIONS,
1226 PackageManager.RESTRICTION_NONE);
1227 if ((distractionRestrictions
1228 & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0) {
1229 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1230 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1231 cancelNotifications = false;
1232 hideNotifications = true;
1233 } else {
1234 pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
1235 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1236 cancelNotifications = false;
1237 unhideNotifications = true;
1238 }
1239
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001240 } else if (queryRestart) {
1241 pkgList = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001242 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001243 } else {
1244 Uri uri = intent.getData();
1245 if (uri == null) {
1246 return;
1247 }
1248 String pkgName = uri.getSchemeSpecificPart();
1249 if (pkgName == null) {
1250 return;
1251 }
Daniel Sandler26ece572012-06-01 15:38:46 -04001252 if (packageChanged) {
1253 // We cancel notifications for packages which have just been disabled
Christopher Tate06e5fed2013-10-09 14:39:15 -07001254 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001255 final int enabled = mPackageManager.getApplicationEnabledSetting(
1256 pkgName,
Kenny Guy70058402014-10-28 20:45:06 +00001257 changeUserId != UserHandle.USER_ALL ? changeUserId :
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001258 USER_SYSTEM);
Christopher Tate06e5fed2013-10-09 14:39:15 -07001259 if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
1260 || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
1261 cancelNotifications = false;
1262 }
1263 } catch (IllegalArgumentException e) {
1264 // Package doesn't exist; probably racing with uninstall.
1265 // cancelNotifications is already true, so nothing to do here.
1266 if (DBG) {
1267 Slog.i(TAG, "Exception trying to look up app enabled setting", e);
1268 }
Kenny Guy70058402014-10-28 20:45:06 +00001269 } catch (RemoteException e) {
1270 // Failed to talk to PackageManagerService Should never happen!
Daniel Sandler26ece572012-06-01 15:38:46 -04001271 }
1272 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001273 pkgList = new String[]{pkgName};
Julia Reynolds4036e8d2017-01-13 09:50:05 -05001274 uidList = new int[] {intent.getIntExtra(Intent.EXTRA_UID, -1)};
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001276 if (pkgList != null && (pkgList.length > 0)) {
woongki minbbc97282019-09-25 11:50:48 +09001277 if (cancelNotifications) {
1278 for (String pkgName : pkgList) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001279 cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, null, 0, 0,
1280 !queryRestart, changeUserId, reason, null);
John Spurlock79f78922013-05-16 09:10:05 -04001281 }
woongki minbbc97282019-09-25 11:50:48 +09001282 } else if (hideNotifications) {
1283 hideNotificationsForPackages(pkgList);
1284 } else if (unhideNotifications) {
1285 unhideNotificationsForPackages(pkgList);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001286 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001288
Julia Reynoldsb0405592018-11-26 17:01:13 -05001289 mHandler.scheduleOnPackageChanged(removingPackage, changeUserId, pkgList, uidList);
Kenny Guy70058402014-10-28 20:45:06 +00001290 }
1291 }
1292 };
1293
1294 private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1295 @Override
1296 public void onReceive(Context context, Intent intent) {
1297 String action = intent.getAction();
1298
1299 if (action.equals(Intent.ACTION_SCREEN_ON)) {
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001300 // Keep track of screen on/off state, but do not turn off the notification light
1301 // until user passes through the lock screen or views the notification.
1302 mScreenOn = true;
Christoph Studer1f32c652014-11-26 15:32:20 +01001303 updateNotificationPulse();
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001304 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1305 mScreenOn = false;
Christoph Studer1f32c652014-11-26 15:32:20 +01001306 updateNotificationPulse();
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001307 } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
Eric Laurent7412abc2019-07-12 18:26:29 -07001308 mInCallStateOffHook = TelephonyManager.EXTRA_STATE_OFFHOOK
John Spurlock5d2eeb12014-01-16 10:46:36 -05001309 .equals(intent.getStringExtra(TelephonyManager.EXTRA_STATE));
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001310 updateNotificationPulse();
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001311 } else if (action.equals(Intent.ACTION_USER_STOPPED)) {
1312 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
1313 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001314 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001315 REASON_USER_STOPPED, null);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001316 }
Rubin Xue95057a2016-04-01 16:49:25 +01001317 } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) {
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001318 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Rubin Xue95057a2016-04-01 16:49:25 +01001319 if (userHandle >= 0) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001320 cancelAllNotificationsInt(MY_UID, MY_PID, null, null, 0, 0, true, userHandle,
Julia Reynoldsef37f282016-02-12 09:11:27 -05001321 REASON_PROFILE_TURNED_OFF, null);
Rubin Xu7eadc1b2016-02-01 16:13:45 +00001322 }
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001323 } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1324 // turn off LED when user passes through lock screen
1325 mNotificationLight.turnOff();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001326 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001327 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
John Spurlockb408e8e2014-04-23 21:12:45 -04001328 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001329 if (!mUserProfiles.isManagedProfile(userId)) {
1330 // reload per-user settings
1331 mSettingsObserver.update(null);
1332 // Refresh managed services
1333 mConditionProviders.onUserSwitched(userId);
1334 mListeners.onUserSwitched(userId);
1335 mZenModeHelper.onUserSwitched(userId);
Beverly0479cde22018-11-09 11:05:34 -05001336 mPreferencesHelper.onUserSwitched(userId);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001337 }
1338 // assistant is the only thing that cares about managed profiles specifically
1339 mAssistants.onUserSwitched(userId);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001340 } else if (action.equals(Intent.ACTION_USER_ADDED)) {
Julia Reynolds88a879f2017-07-26 17:06:46 -04001341 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1342 if (userId != USER_NULL) {
1343 mUserProfiles.updateCache(context);
Julia Reynolds5aa13a42017-08-24 09:10:23 -04001344 if (!mUserProfiles.isManagedProfile(userId)) {
1345 readDefaultApprovedServices(userId);
1346 }
Julia Reynolds88a879f2017-07-26 17:06:46 -04001347 }
John Spurlock21258a32015-05-27 18:22:55 -04001348 } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001349 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001350 mUserProfiles.updateCache(context);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001351 mZenModeHelper.onUserRemoved(userId);
1352 mPreferencesHelper.onUserRemoved(userId);
1353 mListeners.onUserRemoved(userId);
1354 mConditionProviders.onUserRemoved(userId);
1355 mAssistants.onUserRemoved(userId);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001356 handleSavePolicyFile();
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001357 } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
Julia Reynolds4ff97492018-09-24 14:53:54 -04001358 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
1359 mUserProfiles.updateCache(context);
1360 mAssistants.onUserUnlocked(userId);
1361 if (!mUserProfiles.isManagedProfile(userId)) {
1362 mConditionProviders.onUserUnlocked(userId);
1363 mListeners.onUserUnlocked(userId);
1364 mZenModeHelper.onUserUnlocked(userId);
Beverly0479cde22018-11-09 11:05:34 -05001365 mPreferencesHelper.onUserUnlocked(userId);
Julia Reynolds4ff97492018-09-24 14:53:54 -04001366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 }
1368 }
1369 };
1370
John Spurlock7c74f782015-06-04 13:01:42 -04001371 private final class SettingsObserver extends ContentObserver {
Chris Wren89aa2262017-05-05 18:05:56 -04001372 private final Uri NOTIFICATION_BADGING_URI
1373 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
Julia Reynolds4509ce72019-01-31 13:12:43 -05001374 private final Uri NOTIFICATION_BUBBLES_URI
1375 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001376 private final Uri NOTIFICATION_LIGHT_PULSE_URI
1377 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
Chris Wren763a9bb2016-05-31 17:14:12 -04001378 private final Uri NOTIFICATION_RATE_LIMIT_URI
1379 = Settings.Global.getUriFor(Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001380
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001381 SettingsObserver(Handler handler) {
1382 super(handler);
1383 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001384
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001385 void observe() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001386 ContentResolver resolver = getContext().getContentResolver();
Chris Wren89aa2262017-05-05 18:05:56 -04001387 resolver.registerContentObserver(NOTIFICATION_BADGING_URI,
1388 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001389 resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
Daniel Sandler5feceeb2013-03-22 18:29:23 -07001390 false, this, UserHandle.USER_ALL);
Chris Wren763a9bb2016-05-31 17:14:12 -04001391 resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
1392 false, this, UserHandle.USER_ALL);
Julia Reynolds4509ce72019-01-31 13:12:43 -05001393 resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
1394 false, this, UserHandle.USER_ALL);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001395 update(null);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001396 }
1397
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001398 @Override public void onChange(boolean selfChange, Uri uri) {
1399 update(uri);
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001400 }
1401
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001402 public void update(Uri uri) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08001403 ContentResolver resolver = getContext().getContentResolver();
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001404 if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) {
zhoulei7e376972017-05-17 18:41:25 +08001405 boolean pulseEnabled = Settings.System.getIntForUser(resolver,
Julia Reynolds28149f62018-07-03 10:43:35 -04001406 Settings.System.NOTIFICATION_LIGHT_PULSE, 0, UserHandle.USER_CURRENT)
1407 != 0;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001408 if (mNotificationPulseEnabled != pulseEnabled) {
1409 mNotificationPulseEnabled = pulseEnabled;
1410 updateNotificationPulse();
1411 }
1412 }
Chris Wren763a9bb2016-05-31 17:14:12 -04001413 if (uri == null || NOTIFICATION_RATE_LIMIT_URI.equals(uri)) {
1414 mMaxPackageEnqueueRate = Settings.Global.getFloat(resolver,
1415 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE, mMaxPackageEnqueueRate);
1416 }
Chris Wren89aa2262017-05-05 18:05:56 -04001417 if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001418 mPreferencesHelper.updateBadgingEnabled();
Chris Wren89aa2262017-05-05 18:05:56 -04001419 }
Julia Reynolds4509ce72019-01-31 13:12:43 -05001420 if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
1421 mPreferencesHelper.updateBubblesEnabled();
1422 }
Dianne Hackborn1dac2772009-06-26 18:16:48 -07001423 }
1424 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001425
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001426 private SettingsObserver mSettingsObserver;
Beverlyd4f96492017-08-02 13:36:11 -04001427 protected ZenModeHelper mZenModeHelper;
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001428
Daniel Sandleredbb3802012-11-13 20:49:47 -08001429 static long[] getLongArray(Resources r, int resid, int maxlen, long[] def) {
1430 int[] ar = r.getIntArray(resid);
1431 if (ar == null) {
1432 return def;
1433 }
1434 final int len = ar.length > maxlen ? maxlen : ar.length;
1435 long[] out = new long[len];
1436 for (int i=0; i<len; i++) {
1437 out[i] = ar[i];
1438 }
1439 return out;
1440 }
1441
Jeff Brownb880d882014-02-10 19:47:07 -08001442 public NotificationManagerService(Context context) {
1443 super(context);
Dianne Hackborn98305522017-05-05 17:53:53 -07001444 Notification.processWhitelistToken = WHITELIST_TOKEN;
Jeff Brownb880d882014-02-10 19:47:07 -08001445 }
1446
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001447 // TODO - replace these methods with a single VisibleForTesting constructor
Chris Wren93bb8b82016-03-29 14:35:05 -04001448 @VisibleForTesting
1449 void setAudioManager(AudioManager audioMananger) {
1450 mAudioManager = audioMananger;
1451 }
1452
1453 @VisibleForTesting
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05001454 void setHints(int hints) {
1455 mListenerHints = hints;
1456 }
1457
1458 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001459 void setVibrator(Vibrator vibrator) {
1460 mVibrator = vibrator;
1461 }
1462
1463 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001464 void setLights(Light light) {
1465 mNotificationLight = light;
1466 mAttentionLight = light;
Julia Reynolds033a4122017-01-31 16:50:38 -05001467 mNotificationPulseEnabled = true;
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001468 }
1469
1470 @VisibleForTesting
1471 void setScreenOn(boolean on) {
1472 mScreenOn = on;
1473 }
1474
1475 @VisibleForTesting
Julia Reynolds080361e2017-07-13 11:23:12 -04001476 int getNotificationRecordCount() {
1477 synchronized (mNotificationLock) {
1478 int count = mNotificationList.size() + mNotificationsByKey.size()
1479 + mSummaryByGroupKey.size() + mEnqueuedNotifications.size();
1480 // subtract duplicates
1481 for (NotificationRecord posted : mNotificationList) {
1482 if (mNotificationsByKey.containsKey(posted.getKey())) {
1483 count--;
1484 }
1485 if (posted.sbn.isGroup() && posted.getNotification().isGroupSummary()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001486 count--;
Julia Reynolds080361e2017-07-13 11:23:12 -04001487 }
1488 }
1489
1490 return count;
1491 }
1492 }
1493
Julia Reynolds7380d872018-01-12 10:28:26 -05001494 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001495 void clearNotifications() {
1496 mEnqueuedNotifications.clear();
1497 mNotificationList.clear();
1498 mNotificationsByKey.clear();
1499 mSummaryByGroupKey.clear();
1500 }
1501
Julia Reynolds080361e2017-07-13 11:23:12 -04001502 @VisibleForTesting
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001503 void addNotification(NotificationRecord r) {
1504 mNotificationList.add(r);
1505 mNotificationsByKey.put(r.sbn.getKey(), r);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001506 if (r.sbn.isGroup()) {
1507 mSummaryByGroupKey.put(r.getGroupKey(), r);
1508 }
1509 }
1510
1511 @VisibleForTesting
1512 void addEnqueuedNotification(NotificationRecord r) {
1513 mEnqueuedNotifications.add(r);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04001514 }
1515
1516 @VisibleForTesting
Julia Reynolds8617e4e2017-09-18 16:52:37 -04001517 NotificationRecord getNotificationRecord(String key) {
1518 return mNotificationsByKey.get(key);
1519 }
1520
1521
1522 @VisibleForTesting
Chris Wren93bb8b82016-03-29 14:35:05 -04001523 void setSystemReady(boolean systemReady) {
1524 mSystemReady = systemReady;
1525 }
1526
1527 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001528 void setHandler(WorkerHandler handler) {
Chris Wren93bb8b82016-03-29 14:35:05 -04001529 mHandler = handler;
1530 }
1531
Chris Wrend4054312016-06-24 17:07:40 -04001532 @VisibleForTesting
Julia Reynolds0c299d42016-11-15 14:37:04 -05001533 void setFallbackVibrationPattern(long[] vibrationPattern) {
1534 mFallbackVibrationPattern = vibrationPattern;
Chris Wrend4054312016-06-24 17:07:40 -04001535 }
1536
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001537 @VisibleForTesting
1538 void setPackageManager(IPackageManager packageManager) {
1539 mPackageManager = packageManager;
1540 }
1541
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001542 @VisibleForTesting
1543 void setRankingHelper(RankingHelper rankingHelper) {
1544 mRankingHelper = rankingHelper;
1545 }
1546
1547 @VisibleForTesting
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001548 void setPreferencesHelper(PreferencesHelper prefHelper) { mPreferencesHelper = prefHelper; }
1549
1550 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001551 void setRankingHandler(RankingHandler rankingHandler) {
1552 mRankingHandler = rankingHandler;
1553 }
1554
1555 @VisibleForTesting
Julia Reynolds4214da92019-04-10 15:04:06 -04001556 void setZenHelper(ZenModeHelper zenHelper) {
1557 mZenModeHelper = zenHelper;
1558 }
1559
1560 @VisibleForTesting
Adora Zhang963328f2018-11-15 18:17:19 -08001561 void setIsAutomotive(boolean isAutomotive) {
1562 mIsAutomotive = isAutomotive;
1563 }
1564
1565 @VisibleForTesting
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +00001566 void setNotificationEffectsEnabledForAutomotive(boolean isEnabled) {
1567 mNotificationEffectsEnabledForAutomotive = isEnabled;
1568 }
1569
1570 @VisibleForTesting
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05001571 void setIsTelevision(boolean isTelevision) {
1572 mIsTelevision = isTelevision;
1573 }
1574
Julia Reynolds76c096d2017-06-19 08:16:04 -04001575 @VisibleForTesting
1576 void setUsageStats(NotificationUsageStats us) {
1577 mUsageStats = us;
1578 }
1579
Julia Reynolds94187562017-10-10 13:58:49 -04001580 @VisibleForTesting
1581 void setAccessibilityManager(AccessibilityManager am) {
1582 mAccessibilityManager = am;
1583 }
1584
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001585 // TODO: All tests should use this init instead of the one-off setters above.
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05001586 @VisibleForTesting
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001587 void init(Looper looper, IPackageManager packageManager,
1588 PackageManager packageManagerClient,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001589 LightsManager lightsManager, NotificationListeners notificationListeners,
Julia Reynoldsb852e562017-06-06 16:14:18 -04001590 NotificationAssistants notificationAssistants, ConditionProviders conditionProviders,
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001591 ICompanionDeviceManager companionManager, SnoozeHelper snoozeHelper,
Julia Reynolds68263d12017-06-21 14:21:19 -04001592 NotificationUsageStats usageStats, AtomicFile policyFile,
Julia Reynolds7217dc92018-03-07 12:12:09 -05001593 ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001594 UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
Julia Reynolds0c245002019-03-27 16:10:11 -04001595 IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
1596 UserManager userManager) {
Chris Wren54bbef42014-07-09 18:37:56 -04001597 Resources resources = getContext().getResources();
Chris Wren763a9bb2016-05-31 17:14:12 -04001598 mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
1599 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
1600 DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE);
1601
Julia Reynolds94187562017-10-10 13:58:49 -04001602 mAccessibilityManager =
1603 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04001604 mAm = am;
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001605 mUgm = ugm;
1606 mUgmInternal = ugmInternal;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001607 mPackageManager = packageManager;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001608 mPackageManagerClient = packageManagerClient;
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001609 mAppOps = appOps;
Adam Lesinski182f73f2013-12-05 16:48:06 -08001610 mVibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
Julia Reynolds7217dc92018-03-07 12:12:09 -05001611 mAppUsageStats = appUsageStats;
Julia Reynolds2a128742016-11-28 14:29:25 -05001612 mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001613 mCompanionManager = companionManager;
Julia Reynolds68263d12017-06-21 14:21:19 -04001614 mActivityManager = activityManager;
Amith Yamasani396a10c2018-01-19 10:58:07 -08001615 mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
1616 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
Jason Parks50322ff2018-03-27 10:23:33 -05001617 mDpm = dpm;
Julia Reynolds0c245002019-03-27 16:10:11 -04001618 mUm = userManager;
Jason Parks50322ff2018-03-27 10:23:33 -05001619
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001620 mHandler = new WorkerHandler(looper);
Chris Wrenf9536642014-04-17 10:01:54 -04001621 mRankingThread.start();
Chris Wren54bbef42014-07-09 18:37:56 -04001622 String[] extractorNames;
1623 try {
1624 extractorNames = resources.getStringArray(R.array.config_notificationSignalExtractors);
1625 } catch (Resources.NotFoundException e) {
1626 extractorNames = new String[0];
1627 }
Geoffrey Pitschd5bcf212017-06-01 15:45:35 -04001628 mUsageStats = usageStats;
Kenny Guy23991102018-04-05 21:18:38 +01001629 mMetricsLogger = new MetricsLogger();
Chris Wren51017d02015-12-15 15:34:46 -05001630 mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
Julia Reynoldsb852e562017-06-06 16:14:18 -04001631 mConditionProviders = conditionProviders;
John Spurlockb2278d62015-04-07 12:47:12 -04001632 mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
John Spurlock1c923a32014-04-27 16:42:29 -04001633 mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
John Spurlock056c5192014-04-20 21:52:01 -04001634 @Override
1635 public void onConfigChanged() {
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001636 handleSavePolicyFile();
John Spurlock056c5192014-04-20 21:52:01 -04001637 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04001638
1639 @Override
1640 void onZenModeChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001641 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
Jason Monka9927322015-12-13 16:22:37 -05001642 getContext().sendBroadcastAsUser(
Jason Monk63506742015-12-16 12:06:51 -05001643 new Intent(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED_INTERNAL)
1644 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Jason Monka9927322015-12-13 16:22:37 -05001645 UserHandle.ALL, android.Manifest.permission.MANAGE_NOTIFICATIONS);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001646 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02001647 updateInterruptionFilterLocked();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001648 }
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001649 mRankingHandler.requestSort();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001650 }
John Spurlock1fc476d2015-04-14 16:05:20 -04001651
1652 @Override
1653 void onPolicyChanged() {
John Spurlock80774932015-05-07 17:38:50 -04001654 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05001655 mRankingHandler.requestSort();
John Spurlock80774932015-05-07 17:38:50 -04001656 }
John Spurlock056c5192014-04-20 21:52:01 -04001657 });
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001658 mPreferencesHelper = new PreferencesHelper(getContext(),
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001659 mPackageManagerClient,
1660 mRankingHandler,
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001661 mZenModeHelper);
1662 mRankingHelper = new RankingHelper(getContext(),
1663 mRankingHandler,
1664 mPreferencesHelper,
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05001665 mZenModeHelper,
1666 mUsageStats,
1667 extractorNames);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04001668 mSnoozeHelper = snoozeHelper;
Julia Reynolds8aebf352017-06-26 11:35:33 -04001669 mGroupHelper = groupHelper;
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04001670
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05001671 // This is a ManagedServices object that keeps track of the listeners.
1672 mListeners = notificationListeners;
Chris Wren0efdb882016-03-01 17:17:47 -05001673
Julia Reynolds77b2cc92016-11-08 14:41:09 -05001674 // This is a MangedServices object that keeps track of the assistant.
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001675 mAssistants = notificationAssistants;
Julia Reynoldsb852e562017-06-06 16:14:18 -04001676
Kristian Monsen30f59b22018-04-09 10:27:16 +02001677 // Needs to be set before loadPolicyFile
1678 mAllowedManagedServicePackages = this::canUseManagedServices;
1679
Julia Reynoldsb852e562017-06-06 16:14:18 -04001680 mPolicyFile = policyFile;
1681 loadPolicyFile();
Chris Wren0efdb882016-03-01 17:17:47 -05001682
Adam Lesinski182f73f2013-12-05 16:48:06 -08001683 mStatusBar = getLocalService(StatusBarManagerInternal.class);
Wei Liu97e56662016-03-04 10:52:33 -08001684 if (mStatusBar != null) {
1685 mStatusBar.setNotificationDelegate(mNotificationDelegate);
1686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687
Geoffrey Pitsch03533712017-01-05 10:30:07 -05001688 mNotificationLight = lightsManager.getLight(LightsManager.LIGHT_ID_NOTIFICATIONS);
1689 mAttentionLight = lightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
Mike Lockwood3cb67a32009-11-27 14:25:58 -05001690
Daniel Sandleredbb3802012-11-13 20:49:47 -08001691 mFallbackVibrationPattern = getLongArray(resources,
Scott Greenwald9a05b312013-06-28 00:37:54 -04001692 R.array.config_notificationFallbackVibePattern,
Daniel Sandleredbb3802012-11-13 20:49:47 -08001693 VIBRATE_PATTERN_MAXLEN,
1694 DEFAULT_VIBRATE_PATTERN);
Beverly5d463b62017-07-26 14:13:40 -04001695 mInCallNotificationUri = Uri.parse("file://" +
1696 resources.getString(R.string.config_inCallNotificationSound));
1697 mInCallNotificationAudioAttributes = new AudioAttributes.Builder()
1698 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
1699 .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
Beverly5d463b62017-07-26 14:13:40 -04001700 .build();
1701 mInCallNotificationVolume = resources.getFloat(R.dimen.config_inCallNotificationVolume);
1702
Chris Wren5116a822014-06-04 15:59:50 -04001703 mUseAttentionLight = resources.getBoolean(R.bool.config_useAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04001704 mHasLight =
1705 resources.getBoolean(com.android.internal.R.bool.config_intrusiveNotificationLed);
Chris Wren5116a822014-06-04 15:59:50 -04001706
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001707 // Don't start allowing notifications until the setup wizard has run once.
1708 // After that, including subsequent boots, init with notifications turned on.
1709 // This works on the first boot because the setup wizard will toggle this
1710 // flag at least once and we'll go back to 0 after that.
Adam Lesinski182f73f2013-12-05 16:48:06 -08001711 if (0 == Settings.Global.getInt(getContext().getContentResolver(),
Jeff Brownbf6f6f92012-09-25 15:03:20 -07001712 Settings.Global.DEVICE_PROVISIONED, 0)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04001713 mDisableNotificationEffects = true;
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001714 }
John Spurlockb2278d62015-04-07 12:47:12 -04001715 mZenModeHelper.initZenMode();
John Spurlockf3701772015-02-12 13:29:37 -05001716 mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
Joe Onorato39f5b6a2009-07-23 12:29:19 -04001717
John Spurlockb408e8e2014-04-23 21:12:45 -04001718 mUserProfiles.updateCache(getContext());
John Spurlock32fe4c62014-10-02 12:16:02 -04001719 listenForCallState();
Kenny Guya263e4e2014-03-03 18:24:03 +00001720
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001721 mSettingsObserver = new SettingsObserver(mHandler);
1722
1723 mArchive = new Archive(resources.getInteger(
1724 R.integer.config_notificationServiceArchiveSize));
1725
1726 mIsTelevision = mPackageManagerClient.hasSystemFeature(FEATURE_LEANBACK)
1727 || mPackageManagerClient.hasSystemFeature(FEATURE_TELEVISION);
Adora Zhang963328f2018-11-15 18:17:19 -08001728
1729 mIsAutomotive =
1730 mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0);
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +00001731 mNotificationEffectsEnabledForAutomotive =
1732 resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
Julia Reynolds413ba842019-01-11 10:38:08 -05001733
1734 mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
1735 com.android.internal.R.array.config_nonBlockableNotificationPackages));
Julia Reynoldse99db5a2019-04-16 12:50:04 -04001736
1737 mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
1738 com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001739 }
1740
1741 @Override
1742 public void onStart() {
1743 SnoozeHelper snoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
1744 @Override
1745 public void repost(int userId, NotificationRecord r) {
1746 try {
1747 if (DBG) {
1748 Slog.d(TAG, "Reposting " + r.getKey());
1749 }
1750 enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
1751 r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
1752 r.sbn.getNotification(), userId);
1753 } catch (Exception e) {
1754 Slog.e(TAG, "Cannot un-snooze notification", e);
1755 }
1756 }
1757 }, mUserProfiles);
1758
1759 final File systemDir = new File(Environment.getDataDirectory(), "system");
1760
1761 init(Looper.myLooper(),
1762 AppGlobals.getPackageManager(), getContext().getPackageManager(),
1763 getLocalService(LightsManager.class),
1764 new NotificationListeners(AppGlobals.getPackageManager()),
Julia Reynolds7380d872018-01-12 10:28:26 -05001765 new NotificationAssistants(getContext(), mNotificationLock, mUserProfiles,
1766 AppGlobals.getPackageManager()),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001767 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
1768 null, snoozeHelper, new NotificationUsageStats(getContext()),
Julia Reynolds0c245002019-03-27 16:10:11 -04001769 new AtomicFile(new File(
1770 systemDir, "notification_policy.xml"), "notification-policy"),
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001771 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
Julia Reynolds7217dc92018-03-07 12:12:09 -05001772 getGroupHelper(), ActivityManager.getService(),
Jason Parks50322ff2018-03-27 10:23:33 -05001773 LocalServices.getService(UsageStatsManagerInternal.class),
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07001774 LocalServices.getService(DevicePolicyManagerInternal.class),
1775 UriGrantsManager.getService(),
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04001776 LocalServices.getService(UriGrantsManagerInternal.class),
Julia Reynolds0c245002019-03-27 16:10:11 -04001777 (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
1778 getContext().getSystemService(UserManager.class));
Geoffrey Pitschafc00722017-07-18 10:35:22 -04001779
Mike Lockwood35e16bf2010-11-30 19:53:36 -05001780 // register for various Intents
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 IntentFilter filter = new IntentFilter();
Mike Lockwoodc22404a2009-12-02 11:15:02 -05001782 filter.addAction(Intent.ACTION_SCREEN_ON);
1783 filter.addAction(Intent.ACTION_SCREEN_OFF);
Daniel Sandlere96ffb12010-03-11 13:38:06 -05001784 filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
Mike Lockwood63b5ad92011-08-30 09:55:30 -04001785 filter.addAction(Intent.ACTION_USER_PRESENT);
Dianne Hackborn80a4af22012-08-27 19:18:31 -07001786 filter.addAction(Intent.ACTION_USER_STOPPED);
Daniel Sandler4b749ef2013-03-18 21:53:04 -04001787 filter.addAction(Intent.ACTION_USER_SWITCHED);
Kenny Guy3a7c4a52014-03-03 18:24:03 +00001788 filter.addAction(Intent.ACTION_USER_ADDED);
John Spurlock21258a32015-05-27 18:22:55 -04001789 filter.addAction(Intent.ACTION_USER_REMOVED);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -05001790 filter.addAction(Intent.ACTION_USER_UNLOCKED);
Rubin Xue95057a2016-04-01 16:49:25 +01001791 filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001792 getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
Kenny Guy70058402014-10-28 20:45:06 +00001793
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001794 IntentFilter pkgFilter = new IntentFilter();
Chris Wren3da73022013-05-10 14:41:21 -04001795 pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001796 pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
Daniel Sandleraac0eb02011-08-06 22:51:56 -04001797 pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001798 pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
1799 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
1800 pkgFilter.addDataScheme("package");
Kenny Guy70058402014-10-28 20:45:06 +00001801 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
1802 null);
1803
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001804 IntentFilter suspendedPkgFilter = new IntentFilter();
1805 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
Beverly5a20a5e2018-03-06 15:02:44 -05001806 suspendedPkgFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
Julia Reynolds0e5a3432019-01-17 09:40:46 -05001807 suspendedPkgFilter.addAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00001808 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL,
1809 suspendedPkgFilter, null, null);
1810
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001811 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Kenny Guy70058402014-10-28 20:45:06 +00001812 getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
1813 null);
Doug Zongkerab5c49c2009-12-04 10:31:43 -08001814
Julia Reynolds2a128742016-11-28 14:29:25 -05001815 IntentFilter timeoutFilter = new IntentFilter(ACTION_NOTIFICATION_TIMEOUT);
1816 timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
1817 getContext().registerReceiver(mNotificationTimeoutReceiver, timeoutFilter);
1818
Julia Reynoldsb852e562017-06-06 16:14:18 -04001819 IntentFilter settingsRestoredFilter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
1820 getContext().registerReceiver(mRestoreReceiver, settingsRestoredFilter);
1821
Beverlyd4f96492017-08-02 13:36:11 -04001822 IntentFilter localeChangedFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1823 getContext().registerReceiver(mLocaleChangeReceiver, localeChangedFilter);
1824
Vishnu Naire3e4d252018-03-01 11:26:57 -08001825 publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
1826 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
Adam Lesinski182f73f2013-12-05 16:48:06 -08001827 publishLocalService(NotificationManagerInternal.class, mInternalService);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001828 }
1829
Tony Mak9a3c1f12019-03-04 16:04:42 +00001830 private void registerDeviceConfigChange() {
Matt Pape15769e22019-04-19 12:31:24 -07001831 DeviceConfig.addOnPropertiesChangedListener(
Tony Mak9a3c1f12019-03-04 16:04:42 +00001832 DeviceConfig.NAMESPACE_SYSTEMUI,
1833 getContext().getMainExecutor(),
Matt Pape15769e22019-04-19 12:31:24 -07001834 (properties) -> {
1835 if (!DeviceConfig.NAMESPACE_SYSTEMUI.equals(properties.getNamespace())) {
Tony Mak9a3c1f12019-03-04 16:04:42 +00001836 return;
1837 }
Matt Pape15769e22019-04-19 12:31:24 -07001838 if (properties.getKeyset()
1839 .contains(SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE)) {
Tony Mak9a3c1f12019-03-04 16:04:42 +00001840 mAssistants.resetDefaultAssistantsIfNecessary();
1841 }
1842 });
1843 }
1844
1845
Julia Reynolds8aebf352017-06-26 11:35:33 -04001846 private GroupHelper getGroupHelper() {
Adora Zhang48dd614a82018-06-25 19:18:41 -07001847 mAutoGroupAtCount =
1848 getContext().getResources().getInteger(R.integer.config_autoGroupAtCount);
1849 return new GroupHelper(mAutoGroupAtCount, new GroupHelper.Callback() {
Julia Reynolds8aebf352017-06-26 11:35:33 -04001850 @Override
1851 public void addAutoGroup(String key) {
1852 synchronized (mNotificationLock) {
1853 addAutogroupKeyLocked(key);
1854 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001855 }
1856
1857 @Override
1858 public void removeAutoGroup(String key) {
1859 synchronized (mNotificationLock) {
1860 removeAutogroupKeyLocked(key);
1861 }
Julia Reynolds8aebf352017-06-26 11:35:33 -04001862 }
1863
1864 @Override
1865 public void addAutoGroupSummary(int userId, String pkg, String triggeringKey) {
1866 createAutoGroupSummary(userId, pkg, triggeringKey);
1867 }
1868
1869 @Override
1870 public void removeAutoGroupSummary(int userId, String pkg) {
1871 synchronized (mNotificationLock) {
1872 clearAutogroupSummaryLocked(userId, pkg);
1873 }
1874 }
1875 });
1876 }
1877
John Spurlocke7a835b2015-05-13 10:47:05 -04001878 private void sendRegisteredOnlyBroadcast(String action) {
Julia Reynolds4c456dd2019-01-07 12:22:00 -05001879 Intent intent = new Intent(action);
1880 getContext().sendBroadcastAsUser(intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
1881 UserHandle.ALL, null);
1882 // explicitly send the broadcast to all DND packages, even if they aren't currently running
1883 intent.setFlags(0);
1884 final Set<String> dndApprovedPackages = mConditionProviders.getAllowedPackages();
1885 for (String pkg : dndApprovedPackages) {
1886 intent.setPackage(pkg);
1887 getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
1888 }
John Spurlocke7a835b2015-05-13 10:47:05 -04001889 }
1890
Adam Lesinski182f73f2013-12-05 16:48:06 -08001891 @Override
1892 public void onBootPhase(int phase) {
1893 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
1894 // no beeping until we're basically done booting
1895 mSystemReady = true;
Jeff Sharkey098d5802012-04-26 17:30:34 -07001896
Adam Lesinski182f73f2013-12-05 16:48:06 -08001897 // Grab our optional AudioService
1898 mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
John Spurlockcdb57ae2015-02-11 19:04:11 -05001899 mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07001900 mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
John Spurlock661f2cf2014-11-17 10:29:10 -05001901 mZenModeHelper.onSystemReady();
Julia Reynolds0c245002019-03-27 16:10:11 -04001902 mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04001903 mPackageManager, getContext().getMainExecutor());
Julia Reynolds0c245002019-03-27 16:10:11 -04001904 mRoleObserver.init();
Adam Lesinskia6db4ab2014-03-24 12:31:45 -07001905 } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
1906 // This observer will force an update when observe is called, causing us to
1907 // bind to listener services.
1908 mSettingsObserver.observe();
John Spurlockb408e8e2014-04-23 21:12:45 -04001909 mListeners.onBootPhaseAppsCanStart();
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001910 mAssistants.onBootPhaseAppsCanStart();
John Spurlock7340fc82014-04-24 18:50:12 -04001911 mConditionProviders.onBootPhaseAppsCanStart();
Tony Mak9a3c1f12019-03-04 16:04:42 +00001912 registerDeviceConfigChange();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001913 }
1914 }
1915
Julia Reynolds88860ce2017-06-01 16:55:49 -04001916 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04001917 private void updateListenerHintsLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001918 final int hints = calculateHints();
John Spurlockd8afe3c2014-08-01 14:04:07 -04001919 if (hints == mListenerHints) return;
Bryce Lee7219ada2016-04-08 10:54:23 -07001920 ZenLog.traceListenerHintsChanged(mListenerHints, hints, mEffectsSuppressors.size());
John Spurlockd8afe3c2014-08-01 14:04:07 -04001921 mListenerHints = hints;
1922 scheduleListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04001923 }
1924
Julia Reynolds88860ce2017-06-01 16:55:49 -04001925 @GuardedBy("mNotificationLock")
John Spurlockb4782522014-08-22 14:54:46 -04001926 private void updateEffectsSuppressorLocked() {
Bryce Lee7219ada2016-04-08 10:54:23 -07001927 final long updatedSuppressedEffects = calculateSuppressedEffects();
1928 if (updatedSuppressedEffects == mZenModeHelper.getSuppressedEffects()) return;
1929 final List<ComponentName> suppressors = getSuppressors();
1930 ZenLog.traceEffectsSuppressorChanged(mEffectsSuppressors, suppressors, updatedSuppressedEffects);
1931 mEffectsSuppressors = suppressors;
1932 mZenModeHelper.setSuppressedEffects(updatedSuppressedEffects);
John Spurlocke7a835b2015-05-13 10:47:05 -04001933 sendRegisteredOnlyBroadcast(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
John Spurlockb4782522014-08-22 14:54:46 -04001934 }
1935
Amith Yamasani396a10c2018-01-19 10:58:07 -08001936 private void exitIdle() {
1937 try {
1938 if (mDeviceIdleController != null) {
1939 mDeviceIdleController.exitIdle("notification interaction");
1940 }
1941 } catch (RemoteException e) {
1942 }
1943 }
1944
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001945 private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
1946 boolean fromListener) {
Julia Reynolds924eed12017-01-19 09:52:07 -05001947 if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
1948 // cancel
1949 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001950 UserHandle.getUserId(uid), REASON_CHANNEL_BANNED,
Julia Reynolds924eed12017-01-19 09:52:07 -05001951 null);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001952 if (isUidSystemOrPhone(uid)) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001953 IntArray profileIds = mUserProfiles.getCurrentProfileIds();
1954 int N = profileIds.size();
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001955 for (int i = 0; i < N; i++) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001956 int profileId = profileIds.get(i);
Julia Reynolds33bef2c2017-09-05 11:07:18 -04001957 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channel.getId(), 0, 0, true,
1958 profileId, REASON_CHANNEL_BANNED,
1959 null);
1960 }
1961 }
Julia Reynolds924eed12017-01-19 09:52:07 -05001962 }
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001963 final NotificationChannel preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001964 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001965
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001966 mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001967 maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
Julia Reynolds924eed12017-01-19 09:52:07 -05001968
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001969 if (!fromListener) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04001970 final NotificationChannel modifiedChannel =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04001971 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), false);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001972 mListeners.notifyNotificationChannelChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04001973 pkg, UserHandle.getUserHandleForUid(uid),
1974 modifiedChannel, NOTIFICATION_CHANNEL_OR_GROUP_UPDATED);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04001975 }
1976
Julia Reynoldsb62dad42018-11-26 16:33:02 -05001977 handleSavePolicyFile();
Julia Reynolds924eed12017-01-19 09:52:07 -05001978 }
1979
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001980 private void maybeNotifyChannelOwner(String pkg, int uid, NotificationChannel preUpdate,
1981 NotificationChannel update) {
1982 try {
1983 if ((preUpdate.getImportance() == IMPORTANCE_NONE
1984 && update.getImportance() != IMPORTANCE_NONE)
1985 || (preUpdate.getImportance() != IMPORTANCE_NONE
1986 && update.getImportance() == IMPORTANCE_NONE)) {
1987 getContext().sendBroadcastAsUser(
1988 new Intent(ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05001989 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05001990 update.getId())
1991 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
1992 update.getImportance() == IMPORTANCE_NONE)
1993 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
1994 .setPackage(pkg),
1995 UserHandle.of(UserHandle.getUserId(uid)), null);
1996 }
1997 } catch (SecurityException e) {
1998 Slog.w(TAG, "Can't notify app about channel change", e);
1999 }
2000 }
2001
Julia Reynolds005c8b92017-08-24 10:35:53 -04002002 private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
2003 boolean fromApp, boolean fromListener) {
2004 Preconditions.checkNotNull(group);
2005 Preconditions.checkNotNull(pkg);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002006
2007 final NotificationChannelGroup preUpdate =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002008 mPreferencesHelper.getNotificationChannelGroup(group.getId(), pkg, uid);
2009 mPreferencesHelper.createNotificationChannelGroup(pkg, uid, group,
Julia Reynolds005c8b92017-08-24 10:35:53 -04002010 fromApp);
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002011 if (!fromApp) {
2012 maybeNotifyChannelGroupOwner(pkg, uid, preUpdate, group);
2013 }
Julia Reynolds005c8b92017-08-24 10:35:53 -04002014 if (!fromListener) {
2015 mListeners.notifyNotificationChannelGroupChanged(pkg,
2016 UserHandle.of(UserHandle.getCallingUserId()), group,
2017 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
2018 }
2019 }
2020
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002021 private void maybeNotifyChannelGroupOwner(String pkg, int uid,
2022 NotificationChannelGroup preUpdate, NotificationChannelGroup update) {
2023 try {
2024 if (preUpdate.isBlocked() != update.isBlocked()) {
2025 getContext().sendBroadcastAsUser(
2026 new Intent(ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED)
Julia Reynolds44ff7c92018-02-05 10:02:30 -05002027 .putExtra(NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID,
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002028 update.getId())
2029 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE,
2030 update.isBlocked())
2031 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2032 .setPackage(pkg),
2033 UserHandle.of(UserHandle.getUserId(uid)), null);
2034 }
2035 } catch (SecurityException e) {
2036 Slog.w(TAG, "Can't notify app about group change", e);
2037 }
2038 }
2039
Bryce Lee7219ada2016-04-08 10:54:23 -07002040 private ArrayList<ComponentName> getSuppressors() {
2041 ArrayList<ComponentName> names = new ArrayList<ComponentName>();
2042 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04002043 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07002044
Julia Reynolds4703bac2018-09-12 10:39:30 -04002045 for (ComponentName info : serviceInfoList) {
2046 names.add(info);
Bryce Lee7219ada2016-04-08 10:54:23 -07002047 }
2048 }
2049
2050 return names;
2051 }
2052
2053 private boolean removeDisabledHints(ManagedServiceInfo info) {
2054 return removeDisabledHints(info, 0);
2055 }
2056
2057 private boolean removeDisabledHints(ManagedServiceInfo info, int hints) {
2058 boolean removed = false;
2059
2060 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
2061 final int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04002062 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07002063
2064 if (hints == 0 || (hint & hints) == hint) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04002065 removed |= listeners.remove(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07002066 }
2067 }
2068
2069 return removed;
2070 }
2071
2072 private void addDisabledHints(ManagedServiceInfo info, int hints) {
2073 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2074 addDisabledHint(info, HINT_HOST_DISABLE_EFFECTS);
2075 }
2076
2077 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
2078 addDisabledHint(info, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS);
2079 }
2080
2081 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
2082 addDisabledHint(info, HINT_HOST_DISABLE_CALL_EFFECTS);
2083 }
2084 }
2085
2086 private void addDisabledHint(ManagedServiceInfo info, int hint) {
2087 if (mListenersDisablingEffects.indexOfKey(hint) < 0) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04002088 mListenersDisablingEffects.put(hint, new ArraySet<>());
Bryce Lee7219ada2016-04-08 10:54:23 -07002089 }
2090
Julia Reynolds4703bac2018-09-12 10:39:30 -04002091 ArraySet<ComponentName> hintListeners = mListenersDisablingEffects.get(hint);
2092 hintListeners.add(info.component);
Bryce Lee7219ada2016-04-08 10:54:23 -07002093 }
2094
2095 private int calculateHints() {
2096 int hints = 0;
2097 for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
2098 int hint = mListenersDisablingEffects.keyAt(i);
Julia Reynolds4703bac2018-09-12 10:39:30 -04002099 ArraySet<ComponentName> serviceInfoList = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07002100
2101 if (!serviceInfoList.isEmpty()) {
2102 hints |= hint;
2103 }
2104 }
2105
2106 return hints;
2107 }
2108
2109 private long calculateSuppressedEffects() {
2110 int hints = calculateHints();
2111 long suppressedEffects = 0;
2112
2113 if ((hints & HINT_HOST_DISABLE_EFFECTS) != 0) {
2114 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_ALL;
2115 }
2116
2117 if ((hints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
2118 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_NOTIFICATIONS;
2119 }
2120
2121 if ((hints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
2122 suppressedEffects |= ZenModeHelper.SUPPRESSED_EFFECT_CALLS;
2123 }
2124
2125 return suppressedEffects;
2126 }
2127
Julia Reynolds88860ce2017-06-01 16:55:49 -04002128 @GuardedBy("mNotificationLock")
Christoph Studer85a384b2014-08-27 20:16:15 +02002129 private void updateInterruptionFilterLocked() {
2130 int interruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
2131 if (interruptionFilter == mInterruptionFilter) return;
2132 mInterruptionFilter = interruptionFilter;
2133 scheduleInterruptionFilterChanged(interruptionFilter);
2134 }
2135
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05002136 @VisibleForTesting
2137 INotificationManager getBinderService() {
2138 return INotificationManager.Stub.asInterface(mService);
2139 }
2140
Amith Yamasani7ec89412018-02-07 08:48:49 -08002141 /**
2142 * Report to usage stats that the notification was seen.
2143 * @param r notification record
2144 */
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002145 @GuardedBy("mNotificationLock")
Amith Yamasani803eab692017-11-09 17:47:04 -08002146 protected void reportSeen(NotificationRecord r) {
Julia Reynolds95334132018-12-19 11:15:35 -05002147 if (!r.isProxied()) {
2148 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
2149 getRealUserId(r.sbn.getUserId()),
2150 UsageEvents.Event.NOTIFICATION_SEEN);
2151 }
Amith Yamasani803eab692017-11-09 17:47:04 -08002152 }
2153
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002154 protected int calculateSuppressedVisualEffects(Policy incomingPolicy, Policy currPolicy,
2155 int targetSdkVersion) {
2156 if (incomingPolicy.suppressedVisualEffects == SUPPRESSED_EFFECTS_UNSET) {
2157 return incomingPolicy.suppressedVisualEffects;
2158 }
2159 final int[] effectsIntroducedInP = {
2160 SUPPRESSED_EFFECT_FULL_SCREEN_INTENT,
2161 SUPPRESSED_EFFECT_LIGHTS,
2162 SUPPRESSED_EFFECT_PEEK,
2163 SUPPRESSED_EFFECT_STATUS_BAR,
2164 SUPPRESSED_EFFECT_BADGE,
2165 SUPPRESSED_EFFECT_AMBIENT,
2166 SUPPRESSED_EFFECT_NOTIFICATION_LIST
2167 };
2168
2169 int newSuppressedVisualEffects = incomingPolicy.suppressedVisualEffects;
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06002170 if (targetSdkVersion < Build.VERSION_CODES.P) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002171 // unset higher order bits introduced in P, maintain the user's higher order bits
2172 for (int i = 0; i < effectsIntroducedInP.length ; i++) {
2173 newSuppressedVisualEffects &= ~effectsIntroducedInP[i];
2174 newSuppressedVisualEffects |=
2175 (currPolicy.suppressedVisualEffects & effectsIntroducedInP[i]);
2176 }
2177 // set higher order bits according to lower order bits
2178 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2179 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2180 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05002181 }
2182 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2183 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2184 }
2185 } else {
2186 boolean hasNewEffects = (newSuppressedVisualEffects
2187 - SUPPRESSED_EFFECT_SCREEN_ON - SUPPRESSED_EFFECT_SCREEN_OFF) > 0;
2188 // if any of the new effects introduced in P are set
2189 if (hasNewEffects) {
2190 // clear out the deprecated effects
2191 newSuppressedVisualEffects &= ~ (SUPPRESSED_EFFECT_SCREEN_ON
2192 | SUPPRESSED_EFFECT_SCREEN_OFF);
2193
2194 // set the deprecated effects according to the new more specific effects
2195 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) != 0) {
2196 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_ON;
2197 }
2198 if ((newSuppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) != 0
2199 && (newSuppressedVisualEffects
2200 & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) != 0
2201 && (newSuppressedVisualEffects
2202 & Policy.SUPPRESSED_EFFECT_AMBIENT) != 0) {
2203 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_SCREEN_OFF;
2204 }
2205 } else {
2206 // set higher order bits according to lower order bits
2207 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_OFF) != 0) {
2208 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_LIGHTS;
2209 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
2210 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_AMBIENT;
2211 }
2212 if ((newSuppressedVisualEffects & SUPPRESSED_EFFECT_SCREEN_ON) != 0) {
2213 newSuppressedVisualEffects |= SUPPRESSED_EFFECT_PEEK;
2214 }
2215 }
2216 }
2217
2218 return newSuppressedVisualEffects;
2219 }
2220
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002221 @GuardedBy("mNotificationLock")
2222 protected void maybeRecordInterruptionLocked(NotificationRecord r) {
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002223 if (r.isInterruptive() && !r.hasRecordedInterruption()) {
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002224 mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
2225 r.getChannel().getId(),
2226 getRealUserId(r.sbn.getUserId()));
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04002227 r.setRecordedInterruption(true);
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002228 }
2229 }
2230
Amith Yamasani7ec89412018-02-07 08:48:49 -08002231 /**
Esteban Talavera917a71d2018-11-13 07:55:08 +00002232 * Report to usage stats that the user interacted with the notification.
Amith Yamasani7ec89412018-02-07 08:48:49 -08002233 * @param r notification record
2234 */
2235 protected void reportUserInteraction(NotificationRecord r) {
Amith Yamasani7ec89412018-02-07 08:48:49 -08002236 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002237 getRealUserId(r.sbn.getUserId()),
Amith Yamasani7ec89412018-02-07 08:48:49 -08002238 UsageEvents.Event.USER_INTERACTION);
2239 }
2240
Julia Reynolds1fac86e2018-03-07 08:30:37 -05002241 private int getRealUserId(int userId) {
2242 return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
2243 }
2244
Geoffrey Pitsch415e4542017-04-10 13:12:58 -04002245 @VisibleForTesting
2246 NotificationManagerInternal getInternalService() {
2247 return mInternalService;
2248 }
2249
Beverly58b24532018-10-02 09:08:23 -04002250 @VisibleForTesting
2251 final IBinder mService = new INotificationManager.Stub() {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002252 // Toasts
2253 // ============================================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 @Override
Jeff Chang48ecef42018-08-09 16:31:59 +08002256 public void enqueueToast(String pkg, ITransientNotification callback, int duration,
2257 int displayId)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258 {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002259 if (DBG) {
2260 Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
Jeff Chang48ecef42018-08-09 16:31:59 +08002261 + " duration=" + duration + " displayId=" + displayId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002263
2264 if (pkg == null || callback == null) {
Beverly58b24532018-10-02 09:08:23 -04002265 Slog.e(TAG, "Not enqueuing toast. pkg=" + pkg + " callback=" + callback);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002266 return ;
2267 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08002268
Beverly58b24532018-10-02 09:08:23 -04002269 final int callingUid = Binder.getCallingUid();
2270 final boolean isSystemToast = isCallerSystemOrPhone()
2271 || PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
2272 final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
2273 final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
2274 callingUid);
2275
2276 long callingIdentity = Binder.clearCallingIdentity();
2277 try {
2278 final boolean appIsForeground = mActivityManager.getUidImportance(callingUid)
2279 == IMPORTANCE_FOREGROUND;
2280 if (ENABLE_BLOCKED_TOASTS && !isSystemToast && ((notificationsDisabledForPackage
2281 && !appIsForeground) || isPackageSuspended)) {
2282 Slog.e(TAG, "Suppressing toast from package " + pkg
2283 + (isPackageSuspended ? " due to package suspended."
2284 : " by user request."));
2285 return;
2286 }
2287 } finally {
2288 Binder.restoreCallingIdentity(callingIdentity);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002289 }
2290
2291 synchronized (mToastQueue) {
2292 int callingPid = Binder.getCallingPid();
2293 long callingId = Binder.clearCallingIdentity();
2294 try {
2295 ToastRecord record;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002296 int index = indexOfToastLocked(pkg, callback);
2297 // If it's already in the queue, we update it in place, we don't
2298 // move it to the end of the queue.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002299 if (index >= 0) {
2300 record = mToastQueue.get(index);
2301 record.update(duration);
2302 } else {
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002303 // Limit the number of toasts that any given package except the android
2304 // package can enqueue. Prevents DOS attacks and deals with leaks.
2305 if (!isSystemToast) {
2306 int count = 0;
2307 final int N = mToastQueue.size();
2308 for (int i=0; i<N; i++) {
2309 final ToastRecord r = mToastQueue.get(i);
2310 if (r.pkg.equals(pkg)) {
2311 count++;
2312 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
2313 Slog.e(TAG, "Package has already posted " + count
2314 + " toasts. Not showing more. Package=" + pkg);
2315 return;
2316 }
2317 }
2318 }
2319 }
2320
Svetoslav Ganovaa076532016-08-01 19:16:43 -07002321 Binder token = new Binder();
Jeff Chang48ecef42018-08-09 16:31:59 +08002322 mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, displayId);
2323 record = new ToastRecord(callingPid, pkg, callback, duration, token,
2324 displayId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002325 mToastQueue.add(record);
2326 index = mToastQueue.size() - 1;
Beverly Taia7ed0ab2018-06-11 14:50:36 +00002327 keepProcessAliveIfNeededLocked(callingPid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002328 }
2329 // If it's at index 0, it's the current toast. It doesn't matter if it's
2330 // new or just been updated. Call back and tell it to show itself.
2331 // If the callback fails, this will remove it from the list, so don't
2332 // assume that it's valid after this.
2333 if (index == 0) {
2334 showNextToastLocked();
2335 }
2336 } finally {
2337 Binder.restoreCallingIdentity(callingId);
2338 }
2339 }
2340 }
2341
2342 @Override
2343 public void cancelToast(String pkg, ITransientNotification callback) {
2344 Slog.i(TAG, "cancelToast pkg=" + pkg + " callback=" + callback);
2345
2346 if (pkg == null || callback == null) {
2347 Slog.e(TAG, "Not cancelling notification. pkg=" + pkg + " callback=" + callback);
2348 return ;
2349 }
2350
2351 synchronized (mToastQueue) {
2352 long callingId = Binder.clearCallingIdentity();
2353 try {
2354 int index = indexOfToastLocked(pkg, callback);
2355 if (index >= 0) {
2356 cancelToastLocked(index);
2357 } else {
2358 Slog.w(TAG, "Toast already cancelled. pkg=" + pkg
2359 + " callback=" + callback);
2360 }
2361 } finally {
2362 Binder.restoreCallingIdentity(callingId);
2363 }
2364 }
2365 }
2366
2367 @Override
Robert Carr997427342018-02-28 18:06:10 -08002368 public void finishToken(String pkg, ITransientNotification callback) {
2369 synchronized (mToastQueue) {
2370 long callingId = Binder.clearCallingIdentity();
2371 try {
2372 int index = indexOfToastLocked(pkg, callback);
2373 if (index >= 0) {
2374 ToastRecord record = mToastQueue.get(index);
Jeff Chang48ecef42018-08-09 16:31:59 +08002375 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08002376 } else {
2377 Slog.w(TAG, "Toast already killed. pkg=" + pkg
2378 + " callback=" + callback);
2379 }
2380 } finally {
2381 Binder.restoreCallingIdentity(callingId);
2382 }
2383 }
2384 }
2385
2386 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002387 public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002388 Notification notification, int userId) throws RemoteException {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04002389 enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(),
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04002390 Binder.getCallingPid(), tag, id, notification, userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002391 }
2392
2393 @Override
2394 public void cancelNotificationWithTag(String pkg, String tag, int id, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002395 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002396 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2397 Binder.getCallingUid(), userId, true, false, "cancelNotificationWithTag", pkg);
Julia Reynoldse46bb372016-03-17 11:05:58 -04002398 // Don't allow client applications to cancel foreground service notis or autobundled
2399 // summaries.
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002400 final int mustNotHaveFlags = isCallingUidSystem() ? 0 :
Mady Mellor49b1bf12019-03-29 12:00:02 -07002401 (FLAG_FOREGROUND_SERVICE | FLAG_AUTOGROUP_SUMMARY);
John Spurlocke6a7d932014-03-13 12:29:00 -04002402 cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
Geoffrey Pitsch27684152017-05-02 11:41:31 -04002403 mustNotHaveFlags, false, userId, REASON_APP_CANCEL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002404 }
2405
2406 @Override
2407 public void cancelAllNotifications(String pkg, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04002408 checkCallerIsSystemOrSameApp(pkg);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002409
2410 userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2411 Binder.getCallingUid(), userId, true, false, "cancelAllNotifications", pkg);
2412
2413 // Calling from user space, don't allow the canceling of actively
2414 // running foreground services.
John Spurlocke6a7d932014-03-13 12:29:00 -04002415 cancelAllNotificationsInt(Binder.getCallingUid(), Binder.getCallingPid(),
Julia Reynoldse5c60452018-04-30 14:41:36 -04002416 pkg, null, 0, FLAG_FOREGROUND_SERVICE, true, userId,
Julia Reynoldsef37f282016-02-12 09:11:27 -05002417 REASON_APP_CANCEL_ALL, null);
Adam Lesinski182f73f2013-12-05 16:48:06 -08002418 }
2419
2420 @Override
2421 public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
Rohan Shahca0447e2018-03-30 15:18:27 -07002422 enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
Adam Lesinski182f73f2013-12-05 16:48:06 -08002423
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002424 mPreferencesHelper.setEnabled(pkg, uid, enabled);
Howard Ro8b56f752018-08-07 15:44:25 -07002425 mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
2426 .setType(MetricsEvent.TYPE_ACTION)
2427 .setPackageName(pkg)
2428 .setSubtype(enabled ? 1 : 0));
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002429 // Now, cancel any outstanding notifications that are part of a just-disabled app
Julia Reynolds4da79702017-06-01 11:06:10 -04002430 if (!enabled) {
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002431 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
2432 UserHandle.getUserId(uid), REASON_PACKAGE_BANNED, null);
2433 }
Julia Reynoldsfc9767b2018-01-22 17:45:16 -05002434
2435 try {
2436 getContext().sendBroadcastAsUser(
2437 new Intent(ACTION_APP_BLOCK_STATE_CHANGED)
2438 .putExtra(NotificationManager.EXTRA_BLOCKED_STATE, !enabled)
2439 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
2440 .setPackage(pkg),
2441 UserHandle.of(UserHandle.getUserId(uid)), null);
2442 } catch (SecurityException e) {
2443 Slog.w(TAG, "Can't notify app about app block change", e);
2444 }
2445
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002446 handleSavePolicyFile();
Adam Lesinski182f73f2013-12-05 16:48:06 -08002447 }
2448
2449 /**
Rohan Shah590e1b22018-04-10 23:48:47 -04002450 * Updates the enabled state for notifications for the given package (and uid).
2451 * Additionally, this method marks the app importance as locked by the user, which means
2452 * that notifications from the app will <b>not</b> be considered for showing a
2453 * blocking helper.
2454 *
2455 * @param pkg package that owns the notifications to update
2456 * @param uid uid of the app providing notifications
2457 * @param enabled whether notifications should be enabled for the app
2458 *
2459 * @see #setNotificationsEnabledForPackage(String, int, boolean)
2460 */
2461 @Override
2462 public void setNotificationsEnabledWithImportanceLockForPackage(
2463 String pkg, int uid, boolean enabled) {
2464 setNotificationsEnabledForPackage(pkg, uid, enabled);
2465
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002466 mPreferencesHelper.setAppImportanceLocked(pkg, uid);
Rohan Shah590e1b22018-04-10 23:48:47 -04002467 }
2468
2469 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08002470 * Use this when you just want to know if notifications are OK for this package.
2471 */
2472 @Override
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002473 public boolean areNotificationsEnabled(String pkg) {
2474 return areNotificationsEnabledForPackage(pkg, Binder.getCallingUid());
2475 }
2476
2477 /**
2478 * Use this when you just want to know if notifications are OK for this package.
2479 */
2480 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08002481 public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
Evan Laird47dc4542019-04-24 15:10:52 -04002482 enforceSystemOrSystemUIOrSamePackage(pkg,
2483 "Caller not system or systemui or same package");
Julia Reynolds657d1642019-03-27 12:15:57 -04002484 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
2485 getContext().enforceCallingPermission(
2486 android.Manifest.permission.INTERACT_ACROSS_USERS,
2487 "canNotifyAsPackage for uid " + uid);
2488 }
Julia Reynolds5fe2eae2017-05-22 08:45:27 -04002489
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002490 return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
Adam Lesinski182f73f2013-12-05 16:48:06 -08002491 }
2492
Chris Wren54bbef42014-07-09 18:37:56 -04002493 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002494 public boolean areBubblesAllowed(String pkg) {
2495 return areBubblesAllowedForPackage(pkg, Binder.getCallingUid());
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002496 }
2497
2498 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002499 public boolean areBubblesAllowedForPackage(String pkg, int uid) {
2500 enforceSystemOrSystemUIOrSamePackage(pkg,
2501 "Caller not system or systemui or same package");
Julia Reynolds2f7592d2019-03-27 12:17:23 -04002502
2503 if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
2504 getContext().enforceCallingPermission(
2505 android.Manifest.permission.INTERACT_ACROSS_USERS,
2506 "canNotifyAsPackage for uid " + uid);
2507 }
2508
Mady Mellor9db685a2019-01-23 13:23:37 -08002509 return mPreferencesHelper.areBubblesAllowed(pkg, uid);
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002510 }
2511
2512 @Override
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002513 public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
Mady Mellor9db685a2019-01-23 13:23:37 -08002514 enforceSystemOrSystemUI("Caller not system or systemui");
Mady Mellorc39b4ae2019-01-09 17:11:37 -08002515 mPreferencesHelper.setBubblesAllowed(pkg, uid, allowed);
Julia Reynolds33ab8a02018-12-17 16:19:52 -05002516 handleSavePolicyFile();
2517 }
2518
2519 @Override
Mady Mellor9db685a2019-01-23 13:23:37 -08002520 public boolean hasUserApprovedBubblesForPackage(String pkg, int uid) {
2521 enforceSystemOrSystemUI("Caller not system or systemui");
2522 int lockedFields = mPreferencesHelper.getAppLockedFields(pkg, uid);
2523 return (lockedFields & PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE) != 0;
2524 }
2525
2526 @Override
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05002527 public boolean shouldHideSilentStatusIcons(String callingPkg) {
2528 checkCallerIsSameApp(callingPkg);
2529
2530 if (isCallerSystemOrPhone()
2531 || mListeners.isListenerPackage(callingPkg)) {
2532 return mPreferencesHelper.shouldHideSilentStatusIcons();
2533 } else {
2534 throw new SecurityException("Only available for notification listeners");
2535 }
2536 }
2537
2538 @Override
2539 public void setHideSilentStatusIcons(boolean hide) {
2540 checkCallerIsSystem();
2541
2542 mPreferencesHelper.setHideSilentStatusIcons(hide);
2543 handleSavePolicyFile();
2544
2545 mListeners.onStatusBarIconsBehaviorChanged(hide);
2546 }
2547
2548 @Override
Julia Reynoldsef37f282016-02-12 09:11:27 -05002549 public int getPackageImportance(String pkg) {
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002550 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002551 return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
Julia Reynolds81afbcd2016-02-09 14:54:08 -05002552 }
2553
2554 @Override
Julia Reynolds924eed12017-01-19 09:52:07 -05002555 public boolean canShowBadge(String pkg, int uid) {
2556 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002557 return mPreferencesHelper.canShowBadge(pkg, uid);
Julia Reynolds924eed12017-01-19 09:52:07 -05002558 }
2559
2560 @Override
2561 public void setShowBadge(String pkg, int uid, boolean showBadge) {
2562 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002563 mPreferencesHelper.setShowBadge(pkg, uid, showBadge);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002564 handleSavePolicyFile();
Julia Reynolds924eed12017-01-19 09:52:07 -05002565 }
2566
2567 @Override
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002568 public void setNotificationDelegate(String callingPkg, String delegate) {
2569 checkCallerIsSameApp(callingPkg);
2570 final int callingUid = Binder.getCallingUid();
2571 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
Julia Reynoldscbc45e72019-03-07 12:31:52 -05002572 if (delegate == null) {
2573 mPreferencesHelper.revokeNotificationDelegate(callingPkg, Binder.getCallingUid());
2574 handleSavePolicyFile();
2575 } else {
2576 try {
2577 ApplicationInfo info =
2578 mPackageManager.getApplicationInfo(delegate,
2579 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
2580 user.getIdentifier());
2581 if (info != null) {
2582 mPreferencesHelper.setNotificationDelegate(
2583 callingPkg, callingUid, delegate, info.uid);
2584 handleSavePolicyFile();
2585 }
2586 } catch (RemoteException e) {
2587 e.rethrowFromSystemServer();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002588 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002589 }
2590 }
2591
2592 @Override
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002593 public String getNotificationDelegate(String callingPkg) {
2594 // callable by Settings also
2595 checkCallerIsSystemOrSameApp(callingPkg);
2596 return mPreferencesHelper.getNotificationDelegate(callingPkg, Binder.getCallingUid());
2597 }
2598
2599 @Override
Julia Reynolds7a6d07a2019-03-18 11:31:56 -04002600 public boolean canNotifyAsPackage(String callingPkg, String targetPkg, int userId) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002601 checkCallerIsSameApp(callingPkg);
2602 final int callingUid = Binder.getCallingUid();
2603 UserHandle user = UserHandle.getUserHandleForUid(callingUid);
Julia Reynolds7a6d07a2019-03-18 11:31:56 -04002604 if (user.getIdentifier() != userId) {
2605 getContext().enforceCallingPermission(
2606 android.Manifest.permission.INTERACT_ACROSS_USERS,
2607 "canNotifyAsPackage for user " + userId);
2608 }
Julia Reynoldsb4a9e9c2019-03-20 15:46:08 -04002609 if (callingPkg.equals(targetPkg)) {
2610 return true;
2611 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002612 try {
2613 ApplicationInfo info =
2614 mPackageManager.getApplicationInfo(targetPkg,
2615 MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
Julia Reynolds7a6d07a2019-03-18 11:31:56 -04002616 userId);
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04002617 if (info != null) {
2618 return mPreferencesHelper.isDelegateAllowed(
2619 targetPkg, info.uid, callingPkg, callingUid);
2620 }
2621 } catch (RemoteException e) {
2622 // :(
2623 }
2624 return false;
2625 }
2626
2627 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002628 public void updateNotificationChannelGroupForPackage(String pkg, int uid,
2629 NotificationChannelGroup group) throws RemoteException {
2630 enforceSystemOrSystemUI("Caller not system or systemui");
2631 createNotificationChannelGroup(pkg, uid, group, false, false);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002632 handleSavePolicyFile();
Julia Reynolds005c8b92017-08-24 10:35:53 -04002633 }
2634
2635 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002636 public void createNotificationChannelGroups(String pkg,
2637 ParceledListSlice channelGroupList) throws RemoteException {
2638 checkCallerIsSystemOrSameApp(pkg);
2639 List<NotificationChannelGroup> groups = channelGroupList.getList();
2640 final int groupSize = groups.size();
2641 for (int i = 0; i < groupSize; i++) {
2642 final NotificationChannelGroup group = groups.get(i);
Julia Reynolds005c8b92017-08-24 10:35:53 -04002643 createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002644 }
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002645 handleSavePolicyFile();
Julia Reynolds59e152e2017-01-25 17:42:53 -05002646 }
2647
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002648 private void createNotificationChannelsImpl(String pkg, int uid,
2649 ParceledListSlice channelsList) {
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002650 List<NotificationChannel> channels = channelsList.getList();
2651 final int channelsSize = channels.size();
Julia Reynoldsdafd3a42019-05-24 13:33:28 -04002652 boolean needsPolicyFileChange = false;
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002653 for (int i = 0; i < channelsSize; i++) {
2654 final NotificationChannel channel = channels.get(i);
2655 Preconditions.checkNotNull(channel, "channel in list is null");
Julia Reynoldsdafd3a42019-05-24 13:33:28 -04002656 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid,
2657 channel, true /* fromTargetApp */,
2658 mConditionProviders.isPackageOrComponentAllowed(
Julia Reynolds1fe10942018-03-28 12:46:51 -04002659 pkg, UserHandle.getUserId(uid)));
Julia Reynoldsdafd3a42019-05-24 13:33:28 -04002660 if (needsPolicyFileChange) {
2661 mListeners.notifyNotificationChannelChanged(pkg,
2662 UserHandle.getUserHandleForUid(uid),
2663 mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(),
2664 false),
2665 NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
2666 }
Geoffrey Pitsch03533712017-01-05 10:30:07 -05002667 }
Julia Reynoldsdafd3a42019-05-24 13:33:28 -04002668 if (needsPolicyFileChange) {
2669 handleSavePolicyFile();
2670 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002671 }
2672
2673 @Override
Geoffrey Pitsch3560f842017-03-22 16:42:43 -04002674 public void createNotificationChannels(String pkg,
2675 ParceledListSlice channelsList) throws RemoteException {
2676 checkCallerIsSystemOrSameApp(pkg);
2677 createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
2678 }
2679
2680 @Override
2681 public void createNotificationChannelsForPackage(String pkg, int uid,
2682 ParceledListSlice channelsList) throws RemoteException {
2683 checkCallerIsSystem();
2684 createNotificationChannelsImpl(pkg, uid, channelsList);
2685 }
2686
2687 @Override
Julia Reynoldsb4a9e9c2019-03-20 15:46:08 -04002688 public NotificationChannel getNotificationChannel(String callingPkg, int userId,
2689 String targetPkg, String channelId) {
2690 if (canNotifyAsPackage(callingPkg, targetPkg, userId)
2691 || isCallingUidSystem()) {
2692 int targetUid = -1;
2693 try {
2694 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
2695 } catch (NameNotFoundException e) {
2696 /* ignore */
2697 }
2698 return mPreferencesHelper.getNotificationChannel(
2699 targetPkg, targetUid, channelId, false /* includeDeleted */);
2700 }
2701 throw new SecurityException("Pkg " + callingPkg
2702 + " cannot read channels for " + targetPkg + " in " + userId);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002703 }
2704
2705 @Override
2706 public NotificationChannel getNotificationChannelForPackage(String pkg, int uid,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002707 String channelId, boolean includeDeleted) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002708 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002709 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002710 }
2711
2712 @Override
2713 public void deleteNotificationChannel(String pkg, String channelId) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002714 checkCallerIsSystemOrSameApp(pkg);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002715 final int callingUid = Binder.getCallingUid();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002716 if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
2717 throw new IllegalArgumentException("Cannot delete default channel");
2718 }
2719 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, channelId, 0, 0, true,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002720 UserHandle.getUserId(callingUid), REASON_CHANNEL_BANNED, null);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002721 mPreferencesHelper.deleteNotificationChannel(pkg, callingUid, channelId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002722 mListeners.notifyNotificationChannelChanged(pkg,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002723 UserHandle.getUserHandleForUid(callingUid),
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002724 mPreferencesHelper.getNotificationChannel(pkg, callingUid, channelId, true),
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002725 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002726 handleSavePolicyFile();
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002727 }
2728
2729 @Override
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002730 public NotificationChannelGroup getNotificationChannelGroup(String pkg, String groupId) {
2731 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002732 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds3eb3ffd2017-11-16 10:11:32 -05002733 pkg, Binder.getCallingUid(), groupId, false);
2734 }
2735
2736 @Override
Julia Reynolds9bfba592017-03-15 14:03:55 -04002737 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroups(
2738 String pkg) {
2739 checkCallerIsSystemOrSameApp(pkg);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002740 return mPreferencesHelper.getNotificationChannelGroups(
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002741 pkg, Binder.getCallingUid(), false, false, true);
Julia Reynolds9bfba592017-03-15 14:03:55 -04002742 }
2743
2744 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002745 public void deleteNotificationChannelGroup(String pkg, String groupId) {
Julia Reynolds9bfba592017-03-15 14:03:55 -04002746 checkCallerIsSystemOrSameApp(pkg);
2747
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002748 final int callingUid = Binder.getCallingUid();
2749 NotificationChannelGroup groupToDelete =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002750 mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, callingUid);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002751 if (groupToDelete != null) {
2752 List<NotificationChannel> deletedChannels =
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002753 mPreferencesHelper.deleteNotificationChannelGroup(pkg, callingUid, groupId);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002754 for (int i = 0; i < deletedChannels.size(); i++) {
2755 final NotificationChannel deletedChannel = deletedChannels.get(i);
2756 cancelAllNotificationsInt(MY_UID, MY_PID, pkg, deletedChannel.getId(), 0, 0,
2757 true,
2758 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED,
2759 null);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002760 mListeners.notifyNotificationChannelChanged(pkg,
2761 UserHandle.getUserHandleForUid(callingUid),
2762 deletedChannel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002763 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
2764 }
2765 mListeners.notifyNotificationChannelGroupChanged(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04002766 pkg, UserHandle.getUserHandleForUid(callingUid), groupToDelete,
2767 NOTIFICATION_CHANNEL_OR_GROUP_DELETED);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002768 handleSavePolicyFile();
Julia Reynolds9bfba592017-03-15 14:03:55 -04002769 }
Julia Reynolds9bfba592017-03-15 14:03:55 -04002770 }
2771
2772 @Override
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002773 public void updateNotificationChannelForPackage(String pkg, int uid,
2774 NotificationChannel channel) {
Geoffrey Pitsch4dd50062016-12-06 16:41:22 -05002775 enforceSystemOrSystemUI("Caller not system or systemui");
Julia Reynolds924eed12017-01-19 09:52:07 -05002776 Preconditions.checkNotNull(channel);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04002777 updateNotificationChannelInt(pkg, uid, channel, false);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002778 }
2779
2780 @Override
2781 public ParceledListSlice<NotificationChannel> getNotificationChannelsForPackage(String pkg,
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002782 int uid, boolean includeDeleted) {
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002783 enforceSystemOrSystemUI("getNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002784 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002785 }
2786
2787 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002788 public int getNumNotificationChannelsForPackage(String pkg, int uid,
2789 boolean includeDeleted) {
2790 enforceSystemOrSystemUI("getNumNotificationChannelsForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002791 return mPreferencesHelper.getNotificationChannels(pkg, uid, includeDeleted)
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002792 .getList().size();
2793 }
2794
2795 @Override
Julia Reynolds17717f52017-05-09 11:46:06 -04002796 public boolean onlyHasDefaultChannel(String pkg, int uid) {
2797 enforceSystemOrSystemUI("onlyHasDefaultChannel");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002798 return mPreferencesHelper.onlyHasDefaultChannel(pkg, uid);
Julia Reynolds17717f52017-05-09 11:46:06 -04002799 }
2800
2801 @Override
Julia Reynolds41103f42017-03-15 11:36:35 -04002802 public int getDeletedChannelCount(String pkg, int uid) {
2803 enforceSystemOrSystemUI("getDeletedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002804 return mPreferencesHelper.getDeletedChannelCount(pkg, uid);
Julia Reynolds41103f42017-03-15 11:36:35 -04002805 }
2806
2807 @Override
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002808 public int getBlockedChannelCount(String pkg, int uid) {
2809 enforceSystemOrSystemUI("getBlockedChannelCount");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002810 return mPreferencesHelper.getBlockedChannelCount(pkg, uid);
Julia Reynoldsf2e499d2018-03-30 10:36:42 -04002811 }
2812
2813 @Override
Julia Reynolds59e152e2017-01-25 17:42:53 -05002814 public ParceledListSlice<NotificationChannelGroup> getNotificationChannelGroupsForPackage(
2815 String pkg, int uid, boolean includeDeleted) {
Evan Laird47dc4542019-04-24 15:10:52 -04002816 enforceSystemOrSystemUI("getNotificationChannelGroupsForPackage");
Julia Reynolds13ed28b2018-09-21 15:20:13 -04002817 return mPreferencesHelper.getNotificationChannelGroups(
2818 pkg, uid, includeDeleted, true, false);
Julia Reynolds59e152e2017-01-25 17:42:53 -05002819 }
2820
2821 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04002822 public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
2823 String pkg, int uid, String groupId, boolean includeDeleted) {
2824 enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002825 return mPreferencesHelper.getNotificationChannelGroupWithChannels(
Julia Reynolds005c8b92017-08-24 10:35:53 -04002826 pkg, uid, groupId, includeDeleted);
2827 }
2828
2829 @Override
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002830 public NotificationChannelGroup getNotificationChannelGroupForPackage(
2831 String groupId, String pkg, int uid) {
2832 enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002833 return mPreferencesHelper.getNotificationChannelGroup(groupId, pkg, uid);
Geoffrey Pitschdf44b602017-02-03 13:31:50 -05002834 }
2835
2836 @Override
Julia Reynoldsb4a9e9c2019-03-20 15:46:08 -04002837 public ParceledListSlice<NotificationChannel> getNotificationChannels(
2838 String callingPkg, String targetPkg, int userId) {
2839 if (canNotifyAsPackage(callingPkg, targetPkg, userId)
2840 || isCallingUidSystem()) {
2841 int targetUid = -1;
2842 try {
2843 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
2844 } catch (NameNotFoundException e) {
2845 /* ignore */
2846 }
2847 return mPreferencesHelper.getNotificationChannels(
2848 targetPkg, targetUid, false /* includeDeleted */);
2849 }
2850 throw new SecurityException("Pkg " + callingPkg
2851 + " cannot read channels for " + targetPkg + " in " + userId);
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04002852 }
2853
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002854 @Override
Julia Reynoldse273f082018-04-12 13:48:49 -04002855 public int getBlockedAppCount(int userId) {
2856 checkCallerIsSystem();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002857 return mPreferencesHelper.getBlockedAppCount(userId);
Julia Reynoldse273f082018-04-12 13:48:49 -04002858 }
2859
2860 @Override
Beverly0479cde22018-11-09 11:05:34 -05002861 public int getAppsBypassingDndCount(int userId) {
2862 checkCallerIsSystem();
2863 return mPreferencesHelper.getAppsBypassingDndCount(userId);
2864 }
2865
2866 @Override
2867 public ParceledListSlice<NotificationChannel> getNotificationChannelsBypassingDnd(
2868 String pkg, int userId) {
2869 checkCallerIsSystem();
2870 return mPreferencesHelper.getNotificationChannelsBypassingDnd(pkg, userId);
2871 }
2872
2873 @Override
Beverly86d076f2018-04-17 14:44:52 -04002874 public boolean areChannelsBypassingDnd() {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04002875 return mPreferencesHelper.areChannelsBypassingDnd();
Beverly86d076f2018-04-17 14:44:52 -04002876 }
2877
2878 @Override
Julia Reynolds5355e852017-02-07 14:54:13 -05002879 public void clearData(String packageName, int uid, boolean fromApp) throws RemoteException {
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002880 checkCallerIsSystem();
2881
2882 // Cancel posted notifications
2883 cancelAllNotificationsInt(MY_UID, MY_PID, packageName, null, 0, 0, true,
2884 UserHandle.getUserId(Binder.getCallingUid()), REASON_CHANNEL_BANNED, null);
2885
Julia Reynoldsb852e562017-06-06 16:14:18 -04002886 final String[] packages = new String[] {packageName};
2887 final int[] uids = new int[] {uid};
2888
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002889 // Listener & assistant
Julia Reynoldsb852e562017-06-06 16:14:18 -04002890 mListeners.onPackagesChanged(true, packages, uids);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04002891 mAssistants.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002892
2893 // Zen
Julia Reynoldsb852e562017-06-06 16:14:18 -04002894 mConditionProviders.onPackagesChanged(true, packages, uids);
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002895
Julia Reynolds67c1e962019-01-04 14:01:10 -05002896 // Snoozing
2897 mSnoozeHelper.clearData(UserHandle.getUserId(uid), packageName);
2898
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002899 // Reset notification preferences
Julia Reynolds5355e852017-02-07 14:54:13 -05002900 if (!fromApp) {
Julia Reynolds7af51c52019-04-19 11:08:27 -04002901 mPreferencesHelper.clearData(packageName, uid);
Julia Reynolds5355e852017-02-07 14:54:13 -05002902 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002903
Julia Reynoldsb62dad42018-11-26 16:33:02 -05002904 handleSavePolicyFile();
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002905 }
2906
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002907 @Override
Julia Reynolds088c4482019-04-10 12:43:27 -04002908 public List<String> getAllowedAssistantAdjustments(String pkg) {
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002909 checkCallerIsSystemOrSameApp(pkg);
2910
2911 if (!isCallerSystemOrPhone()
2912 && !mAssistants.isPackageAllowed(pkg, UserHandle.getCallingUserId())) {
2913 throw new SecurityException("Not currently an assistant");
2914 }
2915
Julia Reynolds088c4482019-04-10 12:43:27 -04002916 return mAssistants.getAllowedAssistantAdjustments();
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002917 }
2918
2919 @Override
Julia Reynolds088c4482019-04-10 12:43:27 -04002920 public void allowAssistantAdjustment(String adjustmentType) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04002921 checkCallerIsSystemOrSystemUiOrShell();
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002922 mAssistants.allowAdjustmentType(adjustmentType);
2923
2924 handleSavePolicyFile();
2925 }
2926
2927 @Override
Julia Reynolds088c4482019-04-10 12:43:27 -04002928 public void disallowAssistantAdjustment(String adjustmentType) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04002929 checkCallerIsSystemOrSystemUiOrShell();
Julia Reynoldsad6dd352019-03-07 16:46:22 -05002930 mAssistants.disallowAdjustmentType(adjustmentType);
2931
2932 handleSavePolicyFile();
2933 }
Julia Reynolds4036e8d2017-01-13 09:50:05 -05002934
Adam Lesinski182f73f2013-12-05 16:48:06 -08002935 /**
2936 * System-only API for getting a list of current (i.e. not cleared) notifications.
2937 *
2938 * Requires ACCESS_NOTIFICATIONS which is signature|system.
Chris Wrenf9536642014-04-17 10:01:54 -04002939 * @returns A list of all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08002940 */
2941 @Override
2942 public StatusBarNotification[] getActiveNotifications(String callingPkg) {
2943 // enforce() will ensure the calling uid has the correct permission
2944 getContext().enforceCallingOrSelfPermission(
2945 android.Manifest.permission.ACCESS_NOTIFICATIONS,
2946 "NotificationManagerService.getActiveNotifications");
2947
2948 StatusBarNotification[] tmp = null;
2949 int uid = Binder.getCallingUid();
2950
2951 // noteOp will check to make sure the callingPkg matches the uid
2952 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
2953 == AppOpsManager.MODE_ALLOWED) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002954 synchronized (mNotificationLock) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08002955 tmp = new StatusBarNotification[mNotificationList.size()];
2956 final int N = mNotificationList.size();
2957 for (int i=0; i<N; i++) {
2958 tmp[i] = mNotificationList.get(i).sbn;
2959 }
2960 }
2961 }
2962 return tmp;
2963 }
2964
2965 /**
Dan Sandler994349c2015-04-15 11:02:54 -04002966 * Public API for getting a list of current notifications for the calling package/uid.
2967 *
Julia Reynolds573c6532017-01-24 17:44:38 -05002968 * Note that since notification posting is done asynchronously, this will not return
2969 * notifications that are in the process of being posted.
2970 *
Julia Reynoldsd12392c2018-12-17 14:06:04 -05002971 * From {@link Build.VERSION_CODES#Q}, will also return notifications you've posted as
2972 * an app's notification delegate via
2973 * {@link NotificationManager#notifyAsPackage(String, String, int, Notification)}.
2974 *
Dan Sandler994349c2015-04-15 11:02:54 -04002975 * @returns A list of all the package's notifications, in natural order.
2976 */
2977 @Override
2978 public ParceledListSlice<StatusBarNotification> getAppActiveNotifications(String pkg,
2979 int incomingUserId) {
2980 checkCallerIsSystemOrSameApp(pkg);
2981 int userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
2982 Binder.getCallingUid(), incomingUserId, true, false,
2983 "getAppActiveNotifications", pkg);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05002984 synchronized (mNotificationLock) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04002985 final ArrayMap<String, StatusBarNotification> map
2986 = new ArrayMap<>(mNotificationList.size() + mEnqueuedNotifications.size());
Erik Wolsheimer2242b4d2015-11-24 13:22:04 -08002987 final int N = mNotificationList.size();
Dan Sandler994349c2015-04-15 11:02:54 -04002988 for (int i = 0; i < N; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05002989 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
2990 mNotificationList.get(i).sbn);
2991 if (sbn != null) {
2992 map.put(sbn.getKey(), sbn);
2993 }
2994 }
2995 for(NotificationRecord snoozed: mSnoozeHelper.getSnoozed(userId, pkg)) {
2996 StatusBarNotification sbn = sanitizeSbn(pkg, userId, snoozed.sbn);
2997 if (sbn != null) {
2998 map.put(sbn.getKey(), sbn);
2999 }
3000 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003001 final int M = mEnqueuedNotifications.size();
3002 for (int i = 0; i < M; i++) {
Chris Wren6676dab2016-12-21 18:26:27 -05003003 StatusBarNotification sbn = sanitizeSbn(pkg, userId,
3004 mEnqueuedNotifications.get(i).sbn);
3005 if (sbn != null) {
3006 map.put(sbn.getKey(), sbn); // pending update overwrites existing post here
Dan Sandler994349c2015-04-15 11:02:54 -04003007 }
3008 }
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003009 final ArrayList<StatusBarNotification> list = new ArrayList<>(map.size());
3010 list.addAll(map.values());
3011 return new ParceledListSlice<StatusBarNotification>(list);
Dan Sandler994349c2015-04-15 11:02:54 -04003012 }
Dan Sandler994349c2015-04-15 11:02:54 -04003013 }
3014
Chris Wren6676dab2016-12-21 18:26:27 -05003015 private StatusBarNotification sanitizeSbn(String pkg, int userId,
3016 StatusBarNotification sbn) {
Julia Reynoldsd12392c2018-12-17 14:06:04 -05003017 if (sbn.getUserId() == userId) {
3018 if (sbn.getPackageName().equals(pkg) || sbn.getOpPkg().equals(pkg)) {
3019 // We could pass back a cloneLight() but clients might get confused and
3020 // try to send this thing back to notify() again, which would not work
3021 // very well.
3022 return new StatusBarNotification(
3023 sbn.getPackageName(),
3024 sbn.getOpPkg(),
3025 sbn.getId(), sbn.getTag(), sbn.getUid(), sbn.getInitialPid(),
3026 sbn.getNotification().clone(),
3027 sbn.getUser(), sbn.getOverrideGroupKey(), sbn.getPostTime());
3028 }
Chris Wren6676dab2016-12-21 18:26:27 -05003029 }
3030 return null;
3031 }
3032
Dan Sandler994349c2015-04-15 11:02:54 -04003033 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08003034 * System-only API for getting a list of recent (cleared, no longer shown) notifications.
3035 *
3036 * Requires ACCESS_NOTIFICATIONS which is signature|system.
3037 */
3038 @Override
3039 public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
3040 // enforce() will ensure the calling uid has the correct permission
3041 getContext().enforceCallingOrSelfPermission(
3042 android.Manifest.permission.ACCESS_NOTIFICATIONS,
3043 "NotificationManagerService.getHistoricalNotifications");
3044
3045 StatusBarNotification[] tmp = null;
3046 int uid = Binder.getCallingUid();
3047
3048 // noteOp will check to make sure the callingPkg matches the uid
3049 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, callingPkg)
3050 == AppOpsManager.MODE_ALLOWED) {
3051 synchronized (mArchive) {
3052 tmp = mArchive.getArray(count);
3053 }
3054 }
3055 return tmp;
3056 }
3057
3058 /**
3059 * Register a listener binder directly with the notification manager.
3060 *
3061 * Only works with system callers. Apps should extend
3062 * {@link android.service.notification.NotificationListenerService}.
3063 */
3064 @Override
3065 public void registerListener(final INotificationListener listener,
Chris Wren0efdb882016-03-01 17:17:47 -05003066 final ComponentName component, final int userid) {
Christoph Studer3e144d32014-05-22 16:48:40 +02003067 enforceSystemOrSystemUI("INotificationManager.registerListener");
Chris Wren0efdb882016-03-01 17:17:47 -05003068 mListeners.registerService(listener, component, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003069 }
3070
3071 /**
3072 * Remove a listener binder directly
3073 */
3074 @Override
Chris Wrene0ba7eb2016-03-04 17:30:43 -05003075 public void unregisterListener(INotificationListener token, int userid) {
Chris Wrenb7c81092016-03-10 11:41:10 -05003076 mListeners.unregisterService(token, userid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003077 }
3078
3079 /**
3080 * Allow an INotificationListener to simulate a "clear all" operation.
3081 *
3082 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
3083 *
3084 * @param token The binder for the listener, to check that the caller is allowed
3085 */
3086 @Override
John Spurlocka4294292014-03-24 18:02:32 -04003087 public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
John Spurlocke6a7d932014-03-13 12:29:00 -04003088 final int callingUid = Binder.getCallingUid();
3089 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08003090 long identity = Binder.clearCallingIdentity();
3091 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003092 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003093 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Beverly5a20a5e2018-03-06 15:02:44 -05003094
John Spurlocka4294292014-03-24 18:02:32 -04003095 if (keys != null) {
3096 final int N = keys.length;
3097 for (int i = 0; i < N; i++) {
3098 NotificationRecord r = mNotificationsByKey.get(keys[i]);
Griff Hazen335e1f02014-09-11 14:49:31 -07003099 if (r == null) continue;
Kenny Guya263e4e2014-03-03 18:24:03 +00003100 final int userId = r.sbn.getUserId();
3101 if (userId != info.userid && userId != UserHandle.USER_ALL &&
John Spurlockb408e8e2014-04-23 21:12:45 -04003102 !mUserProfiles.isCurrentProfile(userId)) {
Kenny Guya263e4e2014-03-03 18:24:03 +00003103 throw new SecurityException("Disallowed call from listener: "
John Spurlock7340fc82014-04-24 18:50:12 -04003104 + info.service);
Kenny Guya263e4e2014-03-03 18:24:03 +00003105 }
Griff Hazen335e1f02014-09-11 14:49:31 -07003106 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
3107 r.sbn.getPackageName(), r.sbn.getTag(), r.sbn.getId(),
3108 userId);
John Spurlocka4294292014-03-24 18:02:32 -04003109 }
3110 } else {
3111 cancelAllLocked(callingUid, callingPid, info.userid,
Kenny Guya263e4e2014-03-03 18:24:03 +00003112 REASON_LISTENER_CANCEL_ALL, info, info.supportsProfiles());
John Spurlocka4294292014-03-24 18:02:32 -04003113 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003114 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003115 } finally {
3116 Binder.restoreCallingIdentity(identity);
3117 }
3118 }
3119
Chris Wrenab41eec2016-01-04 18:01:27 -05003120 /**
3121 * Handle request from an approved listener to re-enable itself.
3122 *
3123 * @param component The componenet to be re-enabled, caller must match package.
3124 */
3125 @Override
3126 public void requestBindListener(ComponentName component) {
3127 checkCallerIsSystemOrSameApp(component.getPackageName());
3128 long identity = Binder.clearCallingIdentity();
3129 try {
Julia Reynoldse46bb372016-03-17 11:05:58 -04003130 ManagedServices manager =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003131 mAssistants.isComponentEnabledForCurrentProfiles(component)
3132 ? mAssistants
Chris Wrenab41eec2016-01-04 18:01:27 -05003133 : mListeners;
3134 manager.setComponentState(component, true);
3135 } finally {
3136 Binder.restoreCallingIdentity(identity);
3137 }
3138 }
3139
3140 @Override
3141 public void requestUnbindListener(INotificationListener token) {
3142 long identity = Binder.clearCallingIdentity();
3143 try {
3144 // allow bound services to disable themselves
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003145 synchronized (mNotificationLock) {
3146 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3147 info.getOwner().setComponentState(info.component, false);
3148 }
Chris Wrenab41eec2016-01-04 18:01:27 -05003149 } finally {
3150 Binder.restoreCallingIdentity(identity);
3151 }
3152 }
3153
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003154 @Override
3155 public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003156 long identity = Binder.clearCallingIdentity();
3157 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003158 synchronized (mNotificationLock) {
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003159 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04003160 if (keys == null) {
3161 return;
3162 }
3163 ArrayList<NotificationRecord> seen = new ArrayList<>();
3164 final int n = keys.length;
3165 for (int i = 0; i < n; i++) {
3166 NotificationRecord r = mNotificationsByKey.get(keys[i]);
3167 if (r == null) continue;
3168 final int userId = r.sbn.getUserId();
3169 if (userId != info.userid && userId != UserHandle.USER_ALL
3170 && !mUserProfiles.isCurrentProfile(userId)) {
3171 throw new SecurityException("Disallowed call from listener: "
3172 + info.service);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003173 }
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04003174 seen.add(r);
3175 if (!r.isSeen()) {
3176 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
3177 reportSeen(r);
3178 r.setSeen();
3179 maybeRecordInterruptionLocked(r);
3180 }
3181 }
3182 if (!seen.isEmpty()) {
3183 mAssistants.onNotificationsSeenLocked(seen);
Amith Yamasanif47e51e2015-04-17 10:02:15 -07003184 }
3185 }
3186 } finally {
3187 Binder.restoreCallingIdentity(identity);
3188 }
3189 }
3190
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003191 /**
3192 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3193 *
3194 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3195 *
Julia Reynolds79672302017-01-12 08:30:16 -05003196 * @param info The binder for the listener, to check that the caller is allowed
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003197 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04003198 @GuardedBy("mNotificationLock")
John Spurlock7340fc82014-04-24 18:50:12 -04003199 private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
Kenny Guya263e4e2014-03-03 18:24:03 +00003200 int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
John Spurlocka4294292014-03-24 18:02:32 -04003201 cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
Mady Mellor49b1bf12019-03-29 12:00:02 -07003202 FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE,
John Spurlocka4294292014-03-24 18:02:32 -04003203 true,
Kenny Guya263e4e2014-03-03 18:24:03 +00003204 userId, REASON_LISTENER_CANCEL, info);
John Spurlocka4294292014-03-24 18:02:32 -04003205 }
3206
Adam Lesinski182f73f2013-12-05 16:48:06 -08003207 /**
Julia Reynolds79672302017-01-12 08:30:16 -05003208 * Allow an INotificationListener to snooze a single notification until a context.
3209 *
3210 * @param token The binder for the listener, to check that the caller is allowed
3211 */
3212 @Override
3213 public void snoozeNotificationUntilContextFromListener(INotificationListener token,
3214 String key, String snoozeCriterionId) {
3215 long identity = Binder.clearCallingIdentity();
3216 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003217 synchronized (mNotificationLock) {
3218 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3219 snoozeNotificationInt(key, SNOOZE_UNTIL_UNSPECIFIED, snoozeCriterionId, info);
3220 }
Julia Reynolds79672302017-01-12 08:30:16 -05003221 } finally {
3222 Binder.restoreCallingIdentity(identity);
3223 }
3224 }
3225
3226 /**
3227 * Allow an INotificationListener to snooze a single notification until a time.
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003228 *
3229 * @param token The binder for the listener, to check that the caller is allowed
3230 */
3231 @Override
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003232 public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
Julia Reynolds50989772017-02-23 14:32:16 -05003233 long duration) {
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003234 long identity = Binder.clearCallingIdentity();
3235 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003236 synchronized (mNotificationLock) {
3237 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3238 snoozeNotificationInt(key, duration, null, info);
3239 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04003240 } finally {
3241 Binder.restoreCallingIdentity(identity);
3242 }
3243 }
3244
3245 /**
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003246 * Allows the notification assistant to un-snooze a single notification.
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003247 *
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003248 * @param token The binder for the assistant, to check that the caller is allowed
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003249 */
3250 @Override
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003251 public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003252 long identity = Binder.clearCallingIdentity();
3253 try {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003254 synchronized (mNotificationLock) {
3255 final ManagedServiceInfo info =
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003256 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldsfeb73412017-04-18 09:28:22 -04003257 unsnoozeNotificationInt(key, info);
3258 }
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05003259 } finally {
3260 Binder.restoreCallingIdentity(identity);
3261 }
3262 }
3263
3264 /**
Adam Lesinski182f73f2013-12-05 16:48:06 -08003265 * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
3266 *
3267 * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
3268 *
3269 * @param token The binder for the listener, to check that the caller is allowed
3270 */
3271 @Override
3272 public void cancelNotificationFromListener(INotificationListener token, String pkg,
3273 String tag, int id) {
John Spurlocke6a7d932014-03-13 12:29:00 -04003274 final int callingUid = Binder.getCallingUid();
3275 final int callingPid = Binder.getCallingPid();
Adam Lesinski182f73f2013-12-05 16:48:06 -08003276 long identity = Binder.clearCallingIdentity();
3277 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003278 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003279 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Kenny Guya263e4e2014-03-03 18:24:03 +00003280 if (info.supportsProfiles()) {
Tony Mak180a9c42019-03-08 13:33:08 +00003281 Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
Kenny Guya263e4e2014-03-03 18:24:03 +00003282 + "from " + info.component
3283 + " use cancelNotification(key) instead.");
3284 } else {
3285 cancelNotificationFromListenerLocked(info, callingUid, callingPid,
3286 pkg, tag, id, info.userid);
3287 }
Adam Lesinskie8240262014-03-26 16:01:00 -07003288 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003289 } finally {
3290 Binder.restoreCallingIdentity(identity);
3291 }
3292 }
3293
3294 /**
3295 * Allow an INotificationListener to request the list of outstanding notifications seen by
3296 * the current user. Useful when starting up, after which point the listener callbacks
3297 * should be used.
3298 *
3299 * @param token The binder for the listener, to check that the caller is allowed
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003300 * @param keys An array of notification keys to fetch, or null to fetch everything
Chris Wrenf9536642014-04-17 10:01:54 -04003301 * @returns The return value will contain the notifications specified in keys, in that
3302 * order, or if keys is null, all the notifications, in natural order.
Adam Lesinski182f73f2013-12-05 16:48:06 -08003303 */
3304 @Override
Christoph Studercee44ba2014-05-20 18:36:43 +02003305 public ParceledListSlice<StatusBarNotification> getActiveNotificationsFromListener(
Christoph Studerb82bc782014-08-20 14:29:43 +02003306 INotificationListener token, String[] keys, int trim) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003307 synchronized (mNotificationLock) {
John Spurlock7340fc82014-04-24 18:50:12 -04003308 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003309 final boolean getKeys = keys != null;
3310 final int N = getKeys ? keys.length : mNotificationList.size();
Christoph Studerb82bc782014-08-20 14:29:43 +02003311 final ArrayList<StatusBarNotification> list
3312 = new ArrayList<StatusBarNotification>(N);
Christoph Studercee44ba2014-05-20 18:36:43 +02003313 for (int i=0; i<N; i++) {
Dan Sandlerea75fdd2014-08-12 12:29:19 -04003314 final NotificationRecord r = getKeys
3315 ? mNotificationsByKey.get(keys[i])
3316 : mNotificationList.get(i);
Christoph Studerb82bc782014-08-20 14:29:43 +02003317 if (r == null) continue;
3318 StatusBarNotification sbn = r.sbn;
3319 if (!isVisibleToListener(sbn, info)) continue;
3320 StatusBarNotification sbnToSend =
3321 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3322 list.add(sbnToSend);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003323 }
Christoph Studercee44ba2014-05-20 18:36:43 +02003324 return new ParceledListSlice<StatusBarNotification>(list);
Adam Lesinski182f73f2013-12-05 16:48:06 -08003325 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003326 }
3327
Julia Reynoldscf63ff12017-01-24 13:55:48 -05003328 /**
3329 * Allow an INotificationListener to request the list of outstanding snoozed notifications
3330 * seen by the current user. Useful when starting up, after which point the listener
3331 * callbacks should be used.
3332 *
3333 * @param token The binder for the listener, to check that the caller is allowed
3334 * @returns The return value will contain the notifications specified in keys, in that
3335 * order, or if keys is null, all the notifications, in natural order.
3336 */
3337 @Override
3338 public ParceledListSlice<StatusBarNotification> getSnoozedNotificationsFromListener(
3339 INotificationListener token, int trim) {
3340 synchronized (mNotificationLock) {
3341 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3342 List<NotificationRecord> snoozedRecords = mSnoozeHelper.getSnoozed();
3343 final int N = snoozedRecords.size();
3344 final ArrayList<StatusBarNotification> list = new ArrayList<>(N);
3345 for (int i=0; i < N; i++) {
3346 final NotificationRecord r = snoozedRecords.get(i);
3347 if (r == null) continue;
3348 StatusBarNotification sbn = r.sbn;
3349 if (!isVisibleToListener(sbn, info)) continue;
3350 StatusBarNotification sbnToSend =
3351 (trim == TRIM_FULL) ? sbn : sbn.cloneLight();
3352 list.add(sbnToSend);
3353 }
3354 return new ParceledListSlice<>(list);
3355 }
3356 }
3357
Adam Lesinski182f73f2013-12-05 16:48:06 -08003358 @Override
Julia Reynolds4703bac2018-09-12 10:39:30 -04003359 public void clearRequestedListenerHints(INotificationListener token) {
3360 final long identity = Binder.clearCallingIdentity();
3361 try {
3362 synchronized (mNotificationLock) {
3363 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3364 removeDisabledHints(info);
3365 updateListenerHintsLocked();
3366 updateEffectsSuppressorLocked();
3367 }
3368 } finally {
3369 Binder.restoreCallingIdentity(identity);
3370 }
3371 }
3372
3373 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04003374 public void requestHintsFromListener(INotificationListener token, int hints) {
3375 final long identity = Binder.clearCallingIdentity();
3376 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003377 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003378 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
Bryce Lee7219ada2016-04-08 10:54:23 -07003379 final int disableEffectsMask = HINT_HOST_DISABLE_EFFECTS
3380 | HINT_HOST_DISABLE_NOTIFICATION_EFFECTS
3381 | HINT_HOST_DISABLE_CALL_EFFECTS;
3382 final boolean disableEffects = (hints & disableEffectsMask) != 0;
John Spurlockd8afe3c2014-08-01 14:04:07 -04003383 if (disableEffects) {
Bryce Lee7219ada2016-04-08 10:54:23 -07003384 addDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003385 } else {
Bryce Lee7219ada2016-04-08 10:54:23 -07003386 removeDisabledHints(info, hints);
John Spurlockd8afe3c2014-08-01 14:04:07 -04003387 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003388 updateListenerHintsLocked();
John Spurlockb4782522014-08-22 14:54:46 -04003389 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04003390 }
John Spurlockd8afe3c2014-08-01 14:04:07 -04003391 } finally {
3392 Binder.restoreCallingIdentity(identity);
John Spurlock1fa865f2014-07-21 14:56:39 -04003393 }
3394 }
3395
3396 @Override
John Spurlockd8afe3c2014-08-01 14:04:07 -04003397 public int getHintsFromListener(INotificationListener token) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003398 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04003399 return mListenerHints;
John Spurlock1fa865f2014-07-21 14:56:39 -04003400 }
3401 }
3402
3403 @Override
Christoph Studer85a384b2014-08-27 20:16:15 +02003404 public void requestInterruptionFilterFromListener(INotificationListener token,
3405 int interruptionFilter) throws RemoteException {
3406 final long identity = Binder.clearCallingIdentity();
3407 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003408 synchronized (mNotificationLock) {
John Spurlock661f2cf2014-11-17 10:29:10 -05003409 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3410 mZenModeHelper.requestFromListener(info.component, interruptionFilter);
Christoph Studer85a384b2014-08-27 20:16:15 +02003411 updateInterruptionFilterLocked();
3412 }
3413 } finally {
3414 Binder.restoreCallingIdentity(identity);
3415 }
3416 }
3417
3418 @Override
3419 public int getInterruptionFilterFromListener(INotificationListener token)
3420 throws RemoteException {
3421 synchronized (mNotificationLight) {
3422 return mInterruptionFilter;
3423 }
3424 }
3425
3426 @Override
Christoph Studerb82bc782014-08-20 14:29:43 +02003427 public void setOnNotificationPostedTrimFromListener(INotificationListener token, int trim)
3428 throws RemoteException {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003429 synchronized (mNotificationLock) {
Christoph Studerb82bc782014-08-20 14:29:43 +02003430 final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
3431 if (info == null) return;
3432 mListeners.setOnNotificationPostedTrimLocked(info, trim);
3433 }
3434 }
3435
3436 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003437 public int getZenMode() {
3438 return mZenModeHelper.getZenMode();
3439 }
3440
3441 @Override
John Spurlock056c5192014-04-20 21:52:01 -04003442 public ZenModeConfig getZenModeConfig() {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003443 enforceSystemOrSystemUI("INotificationManager.getZenModeConfig");
John Spurlock056c5192014-04-20 21:52:01 -04003444 return mZenModeHelper.getConfig();
3445 }
3446
3447 @Override
John Spurlockb2278d62015-04-07 12:47:12 -04003448 public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003449 enforceSystemOrSystemUI("INotificationManager.setZenMode");
John Spurlockcdb57ae2015-02-11 19:04:11 -05003450 final long identity = Binder.clearCallingIdentity();
3451 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003452 mZenModeHelper.setManualZenMode(mode, conditionId, null, reason);
John Spurlockcdb57ae2015-02-11 19:04:11 -05003453 } finally {
3454 Binder.restoreCallingIdentity(identity);
3455 }
3456 }
3457
3458 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003459 public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003460 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
Julia Reynolds361e82d32016-02-26 18:19:49 -05003461 return mZenModeHelper.getZenRules();
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003462 }
3463
3464 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003465 public AutomaticZenRule getAutomaticZenRule(String id) throws RemoteException {
3466 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003467 enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003468 return mZenModeHelper.getAutomaticZenRule(id);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003469 }
3470
3471 @Override
Julia Reynoldsa94365d2019-04-09 10:48:43 -04003472 public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003473 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3474 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
Julia Reynolds68062072018-08-06 15:38:21 -04003475 if (automaticZenRule.getOwner() == null
3476 && automaticZenRule.getConfigurationActivity() == null) {
3477 throw new NullPointerException(
3478 "Rule must have a conditionproviderservice and/or configuration activity");
3479 }
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003480 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
Julia Reynoldsa94365d2019-04-09 10:48:43 -04003481 if (automaticZenRule.getZenPolicy() != null
3482 && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
3483 throw new IllegalArgumentException("ZenPolicy is only applicable to "
3484 + "INTERRUPTION_FILTER_PRIORITY filters");
3485 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003486 enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003487
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003488 return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
3489 "addAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003490 }
3491
3492 @Override
Julia Reynolds361e82d32016-02-26 18:19:49 -05003493 public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003494 throws RemoteException {
3495 Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
3496 Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
Julia Reynolds68062072018-08-06 15:38:21 -04003497 if (automaticZenRule.getOwner() == null
3498 && automaticZenRule.getConfigurationActivity() == null) {
3499 throw new NullPointerException(
3500 "Rule must have a conditionproviderservice and/or configuration activity");
3501 }
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003502 Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
3503 enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003504
Julia Reynolds361e82d32016-02-26 18:19:49 -05003505 return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003506 "updateAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003507 }
3508
3509 @Override
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003510 public boolean removeAutomaticZenRule(String id) throws RemoteException {
3511 Preconditions.checkNotNull(id, "Id is null");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003512 // Verify that they can modify zen rules.
3513 enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
3514
Julia Reynolds4fe98d62015-10-06 16:23:41 -04003515 return mZenModeHelper.removeAutomaticZenRule(id, "removeAutomaticZenRule");
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003516 }
3517
3518 @Override
Julia Reynoldsc8e54e82015-11-30 16:43:05 -05003519 public boolean removeAutomaticZenRules(String packageName) throws RemoteException {
3520 Preconditions.checkNotNull(packageName, "Package name is null");
3521 enforceSystemOrSystemUI("removeAutomaticZenRules");
3522
3523 return mZenModeHelper.removeAutomaticZenRules(packageName, "removeAutomaticZenRules");
3524 }
3525
3526 @Override
Julia Reynolds43b70cd2016-01-14 15:05:34 -05003527 public int getRuleInstanceCount(ComponentName owner) throws RemoteException {
3528 Preconditions.checkNotNull(owner, "Owner is null");
3529 enforceSystemOrSystemUI("getRuleInstanceCount");
3530
3531 return mZenModeHelper.getCurrentInstanceCount(owner);
3532 }
3533
3534 @Override
Julia Reynolds68062072018-08-06 15:38:21 -04003535 public void setAutomaticZenRuleState(String id, Condition condition) {
3536 Preconditions.checkNotNull(id, "id is null");
3537 Preconditions.checkNotNull(condition, "Condition is null");
3538
3539 enforcePolicyAccess(Binder.getCallingUid(), "setAutomaticZenRuleState");
3540
3541 mZenModeHelper.setAutomaticZenRuleState(id, condition);
3542 }
3543
3544 @Override
John Spurlock80774932015-05-07 17:38:50 -04003545 public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
3546 enforcePolicyAccess(pkg, "setInterruptionFilter");
3547 final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
3548 if (zen == -1) throw new IllegalArgumentException("Invalid filter: " + filter);
3549 final long identity = Binder.clearCallingIdentity();
3550 try {
Julia Reynolds44ad6ff2016-07-06 09:47:45 -04003551 mZenModeHelper.setManualZenMode(zen, null, pkg, "setInterruptionFilter");
John Spurlock80774932015-05-07 17:38:50 -04003552 } finally {
3553 Binder.restoreCallingIdentity(identity);
3554 }
3555 }
3556
3557 @Override
John Spurlocka7d92b12015-05-13 14:48:02 -04003558 public void notifyConditions(final String pkg, IConditionProvider provider,
3559 final Condition[] conditions) {
John Spurlocke77bb362014-04-26 10:24:59 -04003560 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3561 checkCallerIsSystemOrSameApp(pkg);
John Spurlocka7d92b12015-05-13 14:48:02 -04003562 mHandler.post(new Runnable() {
3563 @Override
3564 public void run() {
3565 mConditionProviders.notifyConditions(pkg, info, conditions);
3566 }
3567 });
John Spurlocke77bb362014-04-26 10:24:59 -04003568 }
3569
Julia Reynolds38e6ca42016-08-08 08:38:09 -04003570 @Override
3571 public void requestUnbindProvider(IConditionProvider provider) {
3572 long identity = Binder.clearCallingIdentity();
3573 try {
3574 // allow bound services to disable themselves
3575 final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
3576 info.getOwner().setComponentState(info.component, false);
3577 } finally {
3578 Binder.restoreCallingIdentity(identity);
3579 }
3580 }
3581
3582 @Override
3583 public void requestBindProvider(ComponentName component) {
3584 checkCallerIsSystemOrSameApp(component.getPackageName());
3585 long identity = Binder.clearCallingIdentity();
3586 try {
3587 mConditionProviders.setComponentState(component, true);
3588 } finally {
3589 Binder.restoreCallingIdentity(identity);
3590 }
3591 }
3592
John Spurlocke77bb362014-04-26 10:24:59 -04003593 private void enforceSystemOrSystemUI(String message) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04003594 if (isCallerSystemOrPhone()) return;
John Spurlocke77bb362014-04-26 10:24:59 -04003595 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
3596 message);
John Spurlock7340fc82014-04-24 18:50:12 -04003597 }
3598
Julia Reynolds48034f82016-03-09 10:15:16 -05003599 private void enforceSystemOrSystemUIOrSamePackage(String pkg, String message) {
3600 try {
3601 checkCallerIsSystemOrSameApp(pkg);
3602 } catch (SecurityException e) {
3603 getContext().enforceCallingPermission(
3604 android.Manifest.permission.STATUS_BAR_SERVICE,
3605 message);
3606 }
3607 }
3608
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003609 private void enforcePolicyAccess(int uid, String method) {
3610 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3611 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3612 return;
3613 }
3614 boolean accessAllowed = false;
Julia Reynolds4214da92019-04-10 15:04:06 -04003615 String[] packages = mPackageManagerClient.getPackagesForUid(uid);
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003616 final int packageCount = packages.length;
3617 for (int i = 0; i < packageCount; i++) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003618 if (mConditionProviders.isPackageOrComponentAllowed(
3619 packages[i], UserHandle.getUserId(uid))) {
Julia Reynoldsa47a27f2015-08-24 08:31:47 -04003620 accessAllowed = true;
3621 }
3622 }
3623 if (!accessAllowed) {
3624 Slog.w(TAG, "Notification policy access denied calling " + method);
3625 throw new SecurityException("Notification policy access denied");
3626 }
3627 }
3628
John Spurlock80774932015-05-07 17:38:50 -04003629 private void enforcePolicyAccess(String pkg, String method) {
Julia Reynolds6ee26172015-09-28 11:34:48 -04003630 if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
3631 android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
3632 return;
3633 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04003634 checkCallerIsSameApp(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003635 if (!checkPolicyAccess(pkg)) {
3636 Slog.w(TAG, "Notification policy access denied calling " + method);
3637 throw new SecurityException("Notification policy access denied");
John Spurlock1fc476d2015-04-14 16:05:20 -04003638 }
3639 }
3640
John Spurlock80774932015-05-07 17:38:50 -04003641 private boolean checkPackagePolicyAccess(String pkg) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003642 return mConditionProviders.isPackageOrComponentAllowed(
3643 pkg, getCallingUserHandle().getIdentifier());
John Spurlock80774932015-05-07 17:38:50 -04003644 }
3645
3646 private boolean checkPolicyAccess(String pkg) {
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003647 try {
Jason Parks50322ff2018-03-27 10:23:33 -05003648 int uid = getContext().getPackageManager().getPackageUidAsUser(pkg,
3649 UserHandle.getCallingUserId());
Julia Reynolds0867b3a2016-03-30 17:29:54 -04003650 if (PackageManager.PERMISSION_GRANTED == ActivityManager.checkComponentPermission(
3651 android.Manifest.permission.MANAGE_NOTIFICATIONS, uid,
3652 -1, true)) {
3653 return true;
3654 }
3655 } catch (NameNotFoundException e) {
3656 return false;
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003657 }
Jason Parks50322ff2018-03-27 10:23:33 -05003658 return checkPackagePolicyAccess(pkg)
3659 || mListeners.isComponentEnabledForPackage(pkg)
3660 || (mDpm != null &&
3661 mDpm.isActiveAdminWithPolicy(Binder.getCallingUid(),
3662 DeviceAdminInfo.USES_POLICY_PROFILE_OWNER));
John Spurlock1fc476d2015-04-14 16:05:20 -04003663 }
3664
John Spurlock7340fc82014-04-24 18:50:12 -04003665 @Override
Adam Lesinski182f73f2013-12-05 16:48:06 -08003666 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -06003667 if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
Chris Wrene4b38802015-07-07 15:54:19 -04003668 final DumpFilter filter = DumpFilter.parseFromArguments(args);
Makoto Onukibbb4b222018-06-25 16:01:02 -07003669 final long token = Binder.clearCallingIdentity();
3670 try {
3671 if (filter.stats) {
3672 dumpJson(pw, filter);
3673 } else if (filter.proto) {
3674 dumpProto(fd, filter);
3675 } else if (filter.criticalPriority) {
3676 dumpNotificationRecords(pw, filter);
3677 } else {
3678 dumpImpl(pw, filter);
3679 }
3680 } finally {
3681 Binder.restoreCallingIdentity(token);
Chris Wrene4b38802015-07-07 15:54:19 -04003682 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003683 }
John Spurlockb4782522014-08-22 14:54:46 -04003684
3685 @Override
3686 public ComponentName getEffectsSuppressor() {
Bryce Leeba3d8952016-04-12 12:39:15 -07003687 return !mEffectsSuppressors.isEmpty() ? mEffectsSuppressors.get(0) : null;
John Spurlockb4782522014-08-22 14:54:46 -04003688 }
John Spurlock2b122f42014-08-27 16:29:47 -04003689
3690 @Override
3691 public boolean matchesCallFilter(Bundle extras) {
3692 enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
Christoph Studer12aeda82014-09-23 19:08:56 +02003693 return mZenModeHelper.matchesCallFilter(
Fyodor Kupolov02cb6e72015-09-18 18:20:55 -07003694 Binder.getCallingUserHandle(),
Christoph Studer12aeda82014-09-23 19:08:56 +02003695 extras,
3696 mRankingHelper.findExtractor(ValidateNotificationPeople.class),
3697 MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
3698 MATCHES_CALL_FILTER_TIMEOUT_AFFINITY);
John Spurlock2b122f42014-08-27 16:29:47 -04003699 }
John Spurlock530052a2014-11-30 16:26:19 -05003700
3701 @Override
3702 public boolean isSystemConditionProviderEnabled(String path) {
Julia Reynoldsbb983d202017-01-06 09:54:20 -05003703 enforceSystemOrSystemUI("INotificationManager.isSystemConditionProviderEnabled");
John Spurlockb2278d62015-04-07 12:47:12 -04003704 return mConditionProviders.isSystemProviderEnabled(path);
John Spurlock530052a2014-11-30 16:26:19 -05003705 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08003706
Christopher Tatef9767d62015-04-08 14:35:43 -07003707 // Backup/restore interface
3708 @Override
3709 public byte[] getBackupPayload(int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003710 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003711 if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003712 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
3713 try {
Annie Meng8b646fd2019-02-01 18:46:42 +00003714 writePolicyXml(baos, true /*forBackup*/, user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003715 return baos.toByteArray();
3716 } catch (IOException e) {
3717 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
John Spurlock35ef0a62015-05-28 11:24:10 -04003718 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003719 return null;
3720 }
3721
3722 @Override
3723 public void applyRestore(byte[] payload, int user) {
Julia Reynoldsd78263d2018-01-30 10:40:41 -05003724 checkCallerIsSystem();
John Spurlock35ef0a62015-05-28 11:24:10 -04003725 if (DBG) Slog.d(TAG, "applyRestore u=" + user + " payload="
3726 + (payload != null ? new String(payload, StandardCharsets.UTF_8) : null));
3727 if (payload == null) {
3728 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
3729 return;
3730 }
Julia Reynolds8a613f82018-12-13 14:25:13 -05003731 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
3732 try {
Annie Meng8b646fd2019-02-01 18:46:42 +00003733 readPolicyXml(bais, true /*forRestore*/, user);
Julia Reynolds8a613f82018-12-13 14:25:13 -05003734 handleSavePolicyFile();
3735 } catch (NumberFormatException | XmlPullParserException | IOException e) {
3736 Slog.w(TAG, "applyRestore: error reading payload", e);
John Spurlock35ef0a62015-05-28 11:24:10 -04003737 }
Christopher Tatef9767d62015-04-08 14:35:43 -07003738 }
3739
John Spurlock1fc476d2015-04-14 16:05:20 -04003740 @Override
John Spurlock80774932015-05-07 17:38:50 -04003741 public boolean isNotificationPolicyAccessGranted(String pkg) {
3742 return checkPolicyAccess(pkg);
John Spurlock1fc476d2015-04-14 16:05:20 -04003743 }
3744
3745 @Override
Julia Reynolds48034f82016-03-09 10:15:16 -05003746 public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {;
3747 enforceSystemOrSystemUIOrSamePackage(pkg,
3748 "request policy access status for another package");
Julia Reynoldsa2d01022016-03-18 15:03:43 -04003749 return checkPolicyAccess(pkg);
John Spurlock80774932015-05-07 17:38:50 -04003750 }
3751
3752 @Override
John Spurlock80774932015-05-07 17:38:50 -04003753 public void setNotificationPolicyAccessGranted(String pkg, boolean granted)
3754 throws RemoteException {
Julia Reynolds92febc32017-10-26 11:30:31 -04003755 setNotificationPolicyAccessGrantedForUser(
3756 pkg, getCallingUserHandle().getIdentifier(), granted);
3757 }
3758
3759 @Override
3760 public void setNotificationPolicyAccessGrantedForUser(
3761 String pkg, int userId, boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003762 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003763 final long identity = Binder.clearCallingIdentity();
3764 try {
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05003765 if (mAllowedManagedServicePackages.test(
3766 pkg, userId, mConditionProviders.getRequiredPermission())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003767 mConditionProviders.setPackageOrComponentEnabled(
Julia Reynolds92febc32017-10-26 11:30:31 -04003768 pkg, userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003769
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003770 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds4afe2642019-05-01 08:42:24 -04003771 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003772 .setPackage(pkg)
Julia Reynolds99f72072019-01-14 09:35:22 -05003773 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT),
Julia Reynolds92febc32017-10-26 11:30:31 -04003774 UserHandle.of(userId), null);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003775 handleSavePolicyFile();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003776 }
3777 } finally {
3778 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003779 }
John Spurlock80774932015-05-07 17:38:50 -04003780 }
3781
3782 @Override
3783 public Policy getNotificationPolicy(String pkg) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003784 final long identity = Binder.clearCallingIdentity();
3785 try {
3786 return mZenModeHelper.getNotificationPolicy();
3787 } finally {
3788 Binder.restoreCallingIdentity(identity);
3789 }
3790 }
3791
Beverlyff2df9b2018-10-10 16:54:10 -04003792 @Override
3793 public Policy getConsolidatedNotificationPolicy() {
3794 final long identity = Binder.clearCallingIdentity();
3795 try {
3796 return mZenModeHelper.getConsolidatedNotificationPolicy();
3797 } finally {
3798 Binder.restoreCallingIdentity(identity);
3799 }
3800 }
3801
Beverly6697eff2017-12-14 15:00:27 -05003802 /**
3803 * Sets the notification policy. Apps that target API levels below
Beverly98ef61b2018-02-15 10:36:28 -05003804 * {@link android.os.Build.VERSION_CODES#P} cannot change user-designated values to
Beverlyd6964762018-02-16 14:07:03 -05003805 * allow or disallow {@link Policy#PRIORITY_CATEGORY_ALARMS},
3806 * {@link Policy#PRIORITY_CATEGORY_SYSTEM} and
3807 * {@link Policy#PRIORITY_CATEGORY_MEDIA} from bypassing dnd
Beverly6697eff2017-12-14 15:00:27 -05003808 */
John Spurlock1fc476d2015-04-14 16:05:20 -04003809 @Override
John Spurlock80774932015-05-07 17:38:50 -04003810 public void setNotificationPolicy(String pkg, Policy policy) {
3811 enforcePolicyAccess(pkg, "setNotificationPolicy");
John Spurlock1fc476d2015-04-14 16:05:20 -04003812 final long identity = Binder.clearCallingIdentity();
3813 try {
Beverly6697eff2017-12-14 15:00:27 -05003814 final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(pkg,
3815 0, UserHandle.getUserId(MY_UID));
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003816 Policy currPolicy = mZenModeHelper.getNotificationPolicy();
Beverly6697eff2017-12-14 15:00:27 -05003817
Jeff Sharkeyaa1a9112018-04-10 15:18:12 -06003818 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.P) {
Beverly98ef61b2018-02-15 10:36:28 -05003819 int priorityCategories = policy.priorityCategories;
3820 // ignore alarm and media values from new policy
3821 priorityCategories &= ~Policy.PRIORITY_CATEGORY_ALARMS;
Beverlyd6964762018-02-16 14:07:03 -05003822 priorityCategories &= ~Policy.PRIORITY_CATEGORY_MEDIA;
3823 priorityCategories &= ~Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003824 // use user-designated values
Beverlyd6964762018-02-16 14:07:03 -05003825 priorityCategories |= currPolicy.priorityCategories
3826 & Policy.PRIORITY_CATEGORY_ALARMS;
3827 priorityCategories |= currPolicy.priorityCategories
3828 & Policy.PRIORITY_CATEGORY_MEDIA;
3829 priorityCategories |= currPolicy.priorityCategories
3830 & Policy.PRIORITY_CATEGORY_SYSTEM;
Beverly98ef61b2018-02-15 10:36:28 -05003831
Beverly6697eff2017-12-14 15:00:27 -05003832 policy = new Policy(priorityCategories,
3833 policy.priorityCallSenders, policy.priorityMessageSenders,
3834 policy.suppressedVisualEffects);
3835 }
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05003836 int newVisualEffects = calculateSuppressedVisualEffects(
3837 policy, currPolicy, applicationInfo.targetSdkVersion);
3838 policy = new Policy(policy.priorityCategories,
3839 policy.priorityCallSenders, policy.priorityMessageSenders,
3840 newVisualEffects);
Beverly5e073222018-03-08 10:36:25 -05003841 ZenLog.traceSetNotificationPolicy(pkg, applicationInfo.targetSdkVersion, policy);
John Spurlock1fc476d2015-04-14 16:05:20 -04003842 mZenModeHelper.setNotificationPolicy(policy);
Beverly6697eff2017-12-14 15:00:27 -05003843 } catch (RemoteException e) {
John Spurlock1fc476d2015-04-14 16:05:20 -04003844 } finally {
3845 Binder.restoreCallingIdentity(identity);
3846 }
3847 }
Chris Wren51017d02015-12-15 15:34:46 -05003848
3849 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003850 public List<String> getEnabledNotificationListenerPackages() {
3851 checkCallerIsSystem();
3852 return mListeners.getAllowedPackages(getCallingUserHandle().getIdentifier());
3853 }
3854
3855 @Override
3856 public List<ComponentName> getEnabledNotificationListeners(int userId) {
3857 checkCallerIsSystem();
3858 return mListeners.getAllowedComponents(userId);
3859 }
3860
3861 @Override
Fabian Kozynskid9425662019-01-29 13:08:30 -05003862 public ComponentName getAllowedNotificationAssistantForUser(int userId) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04003863 checkCallerIsSystemOrSystemUiOrShell();
Fabian Kozynskid9425662019-01-29 13:08:30 -05003864 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
3865 if (allowedComponents.size() > 1) {
3866 throw new IllegalStateException(
3867 "At most one NotificationAssistant: " + allowedComponents.size());
3868 }
3869 return CollectionUtils.firstOrNull(allowedComponents);
3870 }
3871
3872 @Override
3873 public ComponentName getAllowedNotificationAssistant() {
3874 return getAllowedNotificationAssistantForUser(getCallingUserHandle().getIdentifier());
3875 }
3876
3877 @Override
Julia Reynoldsb852e562017-06-06 16:14:18 -04003878 public boolean isNotificationListenerAccessGranted(ComponentName listener) {
3879 Preconditions.checkNotNull(listener);
3880 checkCallerIsSystemOrSameApp(listener.getPackageName());
3881 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3882 getCallingUserHandle().getIdentifier());
3883 }
3884
3885 @Override
3886 public boolean isNotificationListenerAccessGrantedForUser(ComponentName listener,
3887 int userId) {
3888 Preconditions.checkNotNull(listener);
3889 checkCallerIsSystem();
3890 return mListeners.isPackageOrComponentAllowed(listener.flattenToString(),
3891 userId);
3892 }
3893
3894 @Override
3895 public boolean isNotificationAssistantAccessGranted(ComponentName assistant) {
3896 Preconditions.checkNotNull(assistant);
3897 checkCallerIsSystemOrSameApp(assistant.getPackageName());
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003898 return mAssistants.isPackageOrComponentAllowed(assistant.flattenToString(),
Julia Reynoldsb852e562017-06-06 16:14:18 -04003899 getCallingUserHandle().getIdentifier());
3900 }
3901
3902 @Override
3903 public void setNotificationListenerAccessGranted(ComponentName listener,
3904 boolean granted) throws RemoteException {
3905 setNotificationListenerAccessGrantedForUser(
3906 listener, getCallingUserHandle().getIdentifier(), granted);
3907 }
3908
3909 @Override
3910 public void setNotificationAssistantAccessGranted(ComponentName assistant,
Tony Mak9a3c1f12019-03-04 16:04:42 +00003911 boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003912 setNotificationAssistantAccessGrantedForUser(
3913 assistant, getCallingUserHandle().getIdentifier(), granted);
3914 }
3915
3916 @Override
3917 public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
Tony Mak9a3c1f12019-03-04 16:04:42 +00003918 boolean granted) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04003919 Preconditions.checkNotNull(listener);
Julia Reynolds0d217642017-08-11 11:26:04 -04003920 checkCallerIsSystemOrShell();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003921 final long identity = Binder.clearCallingIdentity();
3922 try {
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05003923 if (mAllowedManagedServicePackages.test(
3924 listener.getPackageName(), userId, mListeners.getRequiredPermission())) {
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003925 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
3926 userId, false, granted);
3927 mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
3928 userId, true, granted);
Julia Reynoldsb852e562017-06-06 16:14:18 -04003929
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003930 getContext().sendBroadcastAsUser(new Intent(
Julia Reynolds4afe2642019-05-01 08:42:24 -04003931 ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003932 .setPackage(listener.getPackageName())
3933 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
Julia Reynolds92febc32017-10-26 11:30:31 -04003934 UserHandle.of(userId), null);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003935
Julia Reynoldsb62dad42018-11-26 16:33:02 -05003936 handleSavePolicyFile();
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003937 }
3938 } finally {
3939 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003940 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003941 }
3942
3943 @Override
3944 public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
Tony Mak9a3c1f12019-03-04 16:04:42 +00003945 int userId, boolean granted) {
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04003946 checkCallerIsSystemOrSystemUiOrShell();
Julia Reynolds4afe2642019-05-01 08:42:24 -04003947 for (UserInfo ui : mUm.getEnabledProfiles(userId)) {
3948 mAssistants.setUserSet(ui.id, true);
3949 }
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003950 final long identity = Binder.clearCallingIdentity();
3951 try {
Tony Mak9a3c1f12019-03-04 16:04:42 +00003952 setNotificationAssistantAccessGrantedForUserInternal(assistant, userId, granted);
Julia Reynoldse5c680f2017-09-13 09:25:10 -04003953 } finally {
3954 Binder.restoreCallingIdentity(identity);
Julia Reynolds68263d12017-06-21 14:21:19 -04003955 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04003956 }
3957
3958 @Override
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003959 public void applyEnqueuedAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003960 Adjustment adjustment) {
3961 boolean foundEnqueued = false;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003962 final long identity = Binder.clearCallingIdentity();
3963 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05003964 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04003965 mAssistants.checkServiceTokenLocked(token);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003966 int N = mEnqueuedNotifications.size();
3967 for (int i = 0; i < N; i++) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003968 final NotificationRecord r = mEnqueuedNotifications.get(i);
3969 if (Objects.equals(adjustment.getKey(), r.getKey())
Julia Reynolds70aaea72018-07-13 13:38:34 -04003970 && Objects.equals(adjustment.getUser(), r.getUserId())
3971 && mAssistants.isSameUser(token, r.getUserId())) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003972 applyAdjustment(r, adjustment);
3973 r.applyAdjustments();
Julia Reynolds27c0a962018-12-10 12:37:28 -05003974 // importance is checked at the beginning of the
3975 // PostNotificationRunnable, before the signal extractors are run, so
3976 // calculate the final importance here
3977 r.calculateImportance();
Julia Reynolds666ccf02018-06-18 10:19:20 -04003978 foundEnqueued = true;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003979 break;
3980 }
3981 }
Julia Reynolds666ccf02018-06-18 10:19:20 -04003982 if (!foundEnqueued) {
Julia Reynolds666ccf02018-06-18 10:19:20 -04003983 applyAdjustmentFromAssistant(token, adjustment);
3984 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05003985 }
3986 } finally {
3987 Binder.restoreCallingIdentity(identity);
3988 }
3989 }
3990
3991 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05003992 public void applyAdjustmentFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04003993 Adjustment adjustment) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04003994 List<Adjustment> adjustments = new ArrayList<>();
3995 adjustments.add(adjustment);
3996 applyAdjustmentsFromAssistant(token, adjustments);
Julia Reynoldse46bb372016-03-17 11:05:58 -04003997 }
3998
3999 @Override
Julia Reynolds52e64d02016-12-09 15:36:12 -05004000 public void applyAdjustmentsFromAssistant(INotificationListener token,
Julia Reynolds666ccf02018-06-18 10:19:20 -04004001 List<Adjustment> adjustments) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04004002
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004003 boolean needsSort = false;
Julia Reynoldse46bb372016-03-17 11:05:58 -04004004 final long identity = Binder.clearCallingIdentity();
4005 try {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004006 synchronized (mNotificationLock) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004007 mAssistants.checkServiceTokenLocked(token);
Julia Reynoldse46bb372016-03-17 11:05:58 -04004008 for (Adjustment adjustment : adjustments) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04004009 NotificationRecord r = mNotificationsByKey.get(adjustment.getKey());
4010 if (r != null && mAssistants.isSameUser(token, r.getUserId())) {
4011 applyAdjustment(r, adjustment);
Julia Reynolds27c0a962018-12-10 12:37:28 -05004012 // If the assistant has blocked the notification, cancel it
4013 // This will trigger a sort, so we don't have to explicitly ask for
4014 // one here.
4015 if (adjustment.getSignals().containsKey(Adjustment.KEY_IMPORTANCE)
4016 && adjustment.getSignals().getInt(Adjustment.KEY_IMPORTANCE)
4017 == IMPORTANCE_NONE) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004018 cancelNotificationsFromListener(token, new String[]{r.getKey()});
4019 } else {
4020 needsSort = true;
4021 }
Julia Reynolds70aaea72018-07-13 13:38:34 -04004022 }
Julia Reynoldse46bb372016-03-17 11:05:58 -04004023 }
4024 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004025 if (needsSort) {
Julia Reynolds70aaea72018-07-13 13:38:34 -04004026 mRankingHandler.requestSort();
4027 }
Chris Wren51017d02015-12-15 15:34:46 -05004028 } finally {
4029 Binder.restoreCallingIdentity(identity);
4030 }
4031 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004032
4033 @Override
Julia Reynolds005c8b92017-08-24 10:35:53 -04004034 public void updateNotificationChannelGroupFromPrivilegedListener(
4035 INotificationListener token, String pkg, UserHandle user,
4036 NotificationChannelGroup group) throws RemoteException {
4037 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004038 verifyPrivilegedListener(token, user, false);
Julia Reynolds005c8b92017-08-24 10:35:53 -04004039 createNotificationChannelGroup(
4040 pkg, getUidForPackageAndUser(pkg, user), group, false, true);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05004041 handleSavePolicyFile();
Julia Reynolds005c8b92017-08-24 10:35:53 -04004042 }
4043
4044 @Override
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004045 public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004046 String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004047 Preconditions.checkNotNull(channel);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004048 Preconditions.checkNotNull(pkg);
4049 Preconditions.checkNotNull(user);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004050
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004051 verifyPrivilegedListener(token, user, false);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004052 updateNotificationChannelInt(pkg, getUidForPackageAndUser(pkg, user), channel, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004053 }
4054
4055 @Override
4056 public ParceledListSlice<NotificationChannel> getNotificationChannelsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004057 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
4058 Preconditions.checkNotNull(pkg);
4059 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004060 verifyPrivilegedListener(token, user, true);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004061
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004062 return mPreferencesHelper.getNotificationChannels(pkg, getUidForPackageAndUser(pkg, user),
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004063 false /* includeDeleted */);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004064 }
4065
4066 @Override
4067 public ParceledListSlice<NotificationChannelGroup>
4068 getNotificationChannelGroupsFromPrivilegedListener(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004069 INotificationListener token, String pkg, UserHandle user) throws RemoteException {
4070 Preconditions.checkNotNull(pkg);
4071 Preconditions.checkNotNull(user);
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004072 verifyPrivilegedListener(token, user, true);
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004073
4074 List<NotificationChannelGroup> groups = new ArrayList<>();
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004075 groups.addAll(mPreferencesHelper.getNotificationChannelGroups(
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004076 pkg, getUidForPackageAndUser(pkg, user)));
4077 return new ParceledListSlice<>(groups);
4078 }
4079
Zimuzob3b9c262018-10-31 11:54:20 +00004080 @Override
4081 public void setPrivateNotificationsAllowed(boolean allow) {
4082 if (PackageManager.PERMISSION_GRANTED
4083 != getContext().checkCallingPermission(
4084 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
4085 throw new SecurityException(
4086 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
4087 }
4088 if (allow != mLockScreenAllowSecureNotifications) {
4089 mLockScreenAllowSecureNotifications = allow;
Julia Reynoldsb62dad42018-11-26 16:33:02 -05004090 handleSavePolicyFile();
Zimuzob3b9c262018-10-31 11:54:20 +00004091 }
4092 }
4093
4094 @Override
4095 public boolean getPrivateNotificationsAllowed() {
4096 if (PackageManager.PERMISSION_GRANTED
4097 != getContext().checkCallingPermission(
4098 permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
4099 throw new SecurityException(
4100 "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
4101 }
4102 return mLockScreenAllowSecureNotifications;
4103 }
4104
Julia Reynoldsb40cd092019-01-25 09:35:02 -05004105 @Override
4106 public boolean isPackagePaused(String pkg) {
4107 Preconditions.checkNotNull(pkg);
4108 checkCallerIsSameApp(pkg);
4109
4110 boolean isPaused;
4111
4112 final PackageManagerInternal pmi = LocalServices.getService(
4113 PackageManagerInternal.class);
4114 int flags = pmi.getDistractingPackageRestrictions(
4115 pkg, Binder.getCallingUserHandle().getIdentifier());
4116 isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
4117
4118 isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
4119
4120 return isPaused;
4121 }
4122
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004123 private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
4124 boolean assistantAllowed) {
Julia Reynoldsfeb73412017-04-18 09:28:22 -04004125 ManagedServiceInfo info;
4126 synchronized (mNotificationLock) {
4127 info = mListeners.checkServiceTokenLocked(token);
4128 }
Julia Reynoldsda781472017-04-12 09:41:16 -04004129 if (!hasCompanionDevice(info)) {
Julia Reynolds48a6ed92018-10-22 12:52:03 -04004130 synchronized (mNotificationLock) {
4131 if (!assistantAllowed || !mAssistants.isServiceTokenValidLocked(info.service)) {
4132 throw new SecurityException(info + " does not have access");
4133 }
4134 }
Julia Reynoldsda781472017-04-12 09:41:16 -04004135 }
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004136 if (!info.enabledAndUserMatches(user.getIdentifier())) {
4137 throw new SecurityException(info + " does not have access");
4138 }
4139 }
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004140
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04004141 private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
4142 int uid = 0;
4143 long identity = Binder.clearCallingIdentity();
4144 try {
4145 uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
4146 } finally {
4147 Binder.restoreCallingIdentity(identity);
4148 }
4149 return uid;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04004150 }
Julia Reynoldsb852e562017-06-06 16:14:18 -04004151
4152 @Override
4153 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
4154 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
4155 throws RemoteException {
Dan Sandler7647f1d2018-11-26 09:56:26 -05004156 new NotificationShellCmd(NotificationManagerService.this)
4157 .exec(this, in, out, err, args, callback, resultReceiver);
Julia Reynoldsb852e562017-06-06 16:14:18 -04004158 }
John Spurlock1fc476d2015-04-14 16:05:20 -04004159 };
John Spurlocka4294292014-03-24 18:02:32 -04004160
Tony Mak9a3c1f12019-03-04 16:04:42 +00004161 @VisibleForTesting
4162 protected void setNotificationAssistantAccessGrantedForUserInternal(
Julia Reynolds4afe2642019-05-01 08:42:24 -04004163 ComponentName assistant, int baseUserId, boolean granted) {
4164 List<UserInfo> users = mUm.getEnabledProfiles(baseUserId);
4165 if (users != null) {
4166 for (UserInfo user : users) {
4167 int userId = user.id;
4168 if (assistant == null) {
4169 ComponentName allowedAssistant = CollectionUtils.firstOrNull(
4170 mAssistants.getAllowedComponents(userId));
4171 if (allowedAssistant != null) {
4172 setNotificationAssistantAccessGrantedForUserInternal(
4173 allowedAssistant, userId, false);
4174 }
4175 continue;
4176 }
4177 if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(),
4178 userId, mAssistants.getRequiredPermission())) {
4179 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
4180 userId, false, granted);
4181 mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
4182 userId, true, granted);
4183
4184 getContext().sendBroadcastAsUser(
4185 new Intent(ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
4186 .setPackage(assistant.getPackageName())
4187 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY),
4188 UserHandle.of(userId), null);
4189
4190 handleSavePolicyFile();
4191 }
Tony Mak9a3c1f12019-03-04 16:04:42 +00004192 }
Tony Mak9a3c1f12019-03-04 16:04:42 +00004193 }
4194 }
4195
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004196 private void applyAdjustment(NotificationRecord r, Adjustment adjustment) {
4197 if (r == null) {
Julia Reynoldse46bb372016-03-17 11:05:58 -04004198 return;
4199 }
Julia Reynoldsc7dcdc22019-03-25 10:26:14 -04004200 if (adjustment.getSignals() != null) {
4201 final Bundle adjustments = adjustment.getSignals();
4202 Bundle.setDefusable(adjustments, true);
4203 List<String> toRemove = new ArrayList<>();
4204 for (String potentialKey : adjustments.keySet()) {
4205 if (!mAssistants.isAdjustmentAllowed(potentialKey)) {
4206 toRemove.add(potentialKey);
4207 }
Julia Reynolds418a8ff2019-03-21 10:45:10 -04004208 }
Julia Reynoldsc7dcdc22019-03-25 10:26:14 -04004209 for (String removeKey : toRemove) {
4210 adjustments.remove(removeKey);
4211 }
4212 r.addAdjustment(adjustment);
Julia Reynoldse46bb372016-03-17 11:05:58 -04004213 }
4214 }
4215
Julia Reynolds88860ce2017-06-01 16:55:49 -04004216 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004217 void addAutogroupKeyLocked(String key) {
4218 NotificationRecord r = mNotificationsByKey.get(key);
4219 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004220 return;
4221 }
Julia Reynolds51710712017-07-19 13:48:07 -04004222 if (r.sbn.getOverrideGroupKey() == null) {
4223 addAutoGroupAdjustment(r, GroupHelper.AUTOGROUP_KEY);
4224 EventLogTags.writeNotificationAutogrouped(key);
4225 mRankingHandler.requestSort();
4226 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04004227 }
4228
Julia Reynolds88860ce2017-06-01 16:55:49 -04004229 @GuardedBy("mNotificationLock")
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004230 void removeAutogroupKeyLocked(String key) {
4231 NotificationRecord r = mNotificationsByKey.get(key);
4232 if (r == null) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004233 return;
4234 }
Julia Reynolds51710712017-07-19 13:48:07 -04004235 if (r.sbn.getOverrideGroupKey() != null) {
4236 addAutoGroupAdjustment(r, null);
4237 EventLogTags.writeNotificationUnautogrouped(key);
4238 mRankingHandler.requestSort();
4239 }
Julia Reynoldseb3dca72017-07-11 10:39:58 -04004240 }
4241
4242 private void addAutoGroupAdjustment(NotificationRecord r, String overrideGroupKey) {
4243 Bundle signals = new Bundle();
4244 signals.putString(Adjustment.KEY_GROUP_KEY, overrideGroupKey);
4245 Adjustment adjustment =
4246 new Adjustment(r.sbn.getPackageName(), r.getKey(), signals, "", r.sbn.getUserId());
4247 r.addAdjustment(adjustment);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004248 }
4249
4250 // Clears the 'fake' auto-group summary.
Julia Reynolds88860ce2017-06-01 16:55:49 -04004251 @GuardedBy("mNotificationLock")
Julia Reynolds8f488d32016-10-14 10:59:01 -04004252 private void clearAutogroupSummaryLocked(int userId, String pkg) {
4253 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4254 if (summaries != null && summaries.containsKey(pkg)) {
4255 // Clear summary.
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004256 final NotificationRecord removed = findNotificationByKeyLocked(summaries.remove(pkg));
Julia Reynolds8f488d32016-10-14 10:59:01 -04004257 if (removed != null) {
Julia Reynolds0839c022017-06-15 15:24:01 -04004258 boolean wasPosted = removeFromNotificationListsLocked(removed);
Julia Reynolds359e9b12017-08-08 12:40:04 -04004259 cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED, wasPosted, null);
Julia Reynoldse46bb372016-03-17 11:05:58 -04004260 }
4261 }
4262 }
4263
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04004264 @GuardedBy("mNotificationLock")
4265 private boolean hasAutoGroupSummaryLocked(StatusBarNotification sbn) {
4266 ArrayMap<String, String> summaries = mAutobundledSummaries.get(sbn.getUserId());
4267 return summaries != null && summaries.containsKey(sbn.getPackageName());
4268 }
4269
Julia Reynoldse46bb372016-03-17 11:05:58 -04004270 // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
Julia Reynolds8f488d32016-10-14 10:59:01 -04004271 private void createAutoGroupSummary(int userId, String pkg, String triggeringKey) {
4272 NotificationRecord summaryRecord = null;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004273 synchronized (mNotificationLock) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004274 NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
4275 if (notificationRecord == null) {
4276 // The notification could have been cancelled again already. A successive
4277 // adjustment will post a summary if needed.
4278 return;
Julia Reynoldse46bb372016-03-17 11:05:58 -04004279 }
Julia Reynolds8f488d32016-10-14 10:59:01 -04004280 final StatusBarNotification adjustedSbn = notificationRecord.sbn;
4281 userId = adjustedSbn.getUser().getIdentifier();
4282 ArrayMap<String, String> summaries = mAutobundledSummaries.get(userId);
4283 if (summaries == null) {
4284 summaries = new ArrayMap<>();
4285 }
4286 mAutobundledSummaries.put(userId, summaries);
4287 if (!summaries.containsKey(pkg)) {
4288 // Add summary
4289 final ApplicationInfo appInfo =
4290 adjustedSbn.getNotification().extras.getParcelable(
4291 Notification.EXTRA_BUILDER_APPLICATION_INFO);
4292 final Bundle extras = new Bundle();
4293 extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004294 final String channelId = notificationRecord.getChannel().getId();
Julia Reynolds8f488d32016-10-14 10:59:01 -04004295 final Notification summaryNotification =
Geoffrey Pitschaf759c52017-02-15 09:35:38 -05004296 new Notification.Builder(getContext(), channelId)
4297 .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
Julia Reynolds8f488d32016-10-14 10:59:01 -04004298 .setGroupSummary(true)
Julia Reynolds9d5786e2017-04-28 10:26:32 -04004299 .setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN)
Julia Reynolds8f488d32016-10-14 10:59:01 -04004300 .setGroup(GroupHelper.AUTOGROUP_KEY)
Mady Mellor49b1bf12019-03-29 12:00:02 -07004301 .setFlag(FLAG_AUTOGROUP_SUMMARY, true)
Julia Reynolds8f488d32016-10-14 10:59:01 -04004302 .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
4303 .setColor(adjustedSbn.getNotification().color)
4304 .setLocalOnly(true)
4305 .build();
4306 summaryNotification.extras.putAll(extras);
4307 Intent appIntent = getContext().getPackageManager().getLaunchIntentForPackage(pkg);
4308 if (appIntent != null) {
4309 summaryNotification.contentIntent = PendingIntent.getActivityAsUser(
4310 getContext(), 0, appIntent, 0, null, UserHandle.of(userId));
4311 }
4312 final StatusBarNotification summarySbn =
4313 new StatusBarNotification(adjustedSbn.getPackageName(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004314 adjustedSbn.getOpPkg(),
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004315 Integer.MAX_VALUE,
Julia Reynolds8f488d32016-10-14 10:59:01 -04004316 GroupHelper.AUTOGROUP_KEY, adjustedSbn.getUid(),
4317 adjustedSbn.getInitialPid(), summaryNotification,
4318 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
4319 System.currentTimeMillis());
Julia Reynolds924eed12017-01-19 09:52:07 -05004320 summaryRecord = new NotificationRecord(getContext(), summarySbn,
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004321 notificationRecord.getChannel());
Rohan Shah590e1b22018-04-10 23:48:47 -04004322 summaryRecord.setIsAppImportanceLocked(
4323 notificationRecord.getIsAppImportanceLocked());
Julia Reynolds8f488d32016-10-14 10:59:01 -04004324 summaries.put(pkg, summarySbn.getKey());
4325 }
4326 }
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004327 if (summaryRecord != null && checkDisqualifyingFeatures(userId, MY_UID,
Julia Reynolds5e702192017-08-18 09:22:40 -04004328 summaryRecord.sbn.getId(), summaryRecord.sbn.getTag(), summaryRecord, true)) {
Julia Reynolds8f488d32016-10-14 10:59:01 -04004329 mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
Julia Reynoldse46bb372016-03-17 11:05:58 -04004330 }
4331 }
4332
John Spurlock32fe4c62014-10-02 12:16:02 -04004333 private String disableNotificationEffects(NotificationRecord record) {
4334 if (mDisableNotificationEffects) {
4335 return "booleanState";
4336 }
4337 if ((mListenerHints & HINT_HOST_DISABLE_EFFECTS) != 0) {
4338 return "listenerHints";
4339 }
Julia Reynoldsdb7081e2019-01-03 14:35:38 -05004340 if (record != null && record.getAudioAttributes() != null) {
4341 if ((mListenerHints & HINT_HOST_DISABLE_NOTIFICATION_EFFECTS) != 0) {
4342 if (record.getAudioAttributes().getUsage()
4343 != AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4344 return "listenerNoti";
4345 }
4346 }
4347 if ((mListenerHints & HINT_HOST_DISABLE_CALL_EFFECTS) != 0) {
4348 if (record.getAudioAttributes().getUsage()
4349 == AudioAttributes.USAGE_VOICE_COMMUNICATION) {
4350 return "listenerCall";
4351 }
4352 }
4353 }
John Spurlock32fe4c62014-10-02 12:16:02 -04004354 if (mCallState != TelephonyManager.CALL_STATE_IDLE && !mZenModeHelper.isCall(record)) {
4355 return "callState";
4356 }
4357 return null;
Chris Wrene4b38802015-07-07 15:54:19 -04004358 };
4359
Kweku Adams887f09c2017-11-13 17:12:20 -08004360 private void dumpJson(PrintWriter pw, @NonNull DumpFilter filter) {
Chris Wrene4b38802015-07-07 15:54:19 -04004361 JSONObject dump = new JSONObject();
4362 try {
4363 dump.put("service", "Notification Manager");
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004364 dump.put("bans", mPreferencesHelper.dumpBansJson(filter));
4365 dump.put("ranking", mPreferencesHelper.dumpJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04004366 dump.put("stats", mUsageStats.dumpJson(filter));
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004367 dump.put("channels", mPreferencesHelper.dumpChannelsJson(filter));
Chris Wrene4b38802015-07-07 15:54:19 -04004368 } catch (JSONException e) {
4369 e.printStackTrace();
4370 }
4371 pw.println(dump);
John Spurlock1fa865f2014-07-21 14:56:39 -04004372 }
4373
Kweku Adams887f09c2017-11-13 17:12:20 -08004374 private void dumpProto(FileDescriptor fd, @NonNull DumpFilter filter) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004375 final ProtoOutputStream proto = new ProtoOutputStream(fd);
4376 synchronized (mNotificationLock) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004377 int N = mNotificationList.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004378 for (int i = 0; i < N; i++) {
4379 final NotificationRecord nr = mNotificationList.get(i);
4380 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4381 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4382 NotificationRecordProto.POSTED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004383 }
4384 N = mEnqueuedNotifications.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004385 for (int i = 0; i < N; i++) {
4386 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4387 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4388 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4389 NotificationRecordProto.ENQUEUED);
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004390 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004391 List<NotificationRecord> snoozed = mSnoozeHelper.getSnoozed();
4392 N = snoozed.size();
Kweku Adamsbc84aec2018-01-23 13:33:12 -08004393 for (int i = 0; i < N; i++) {
4394 final NotificationRecord nr = snoozed.get(i);
4395 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4396 nr.dump(proto, NotificationServiceDumpProto.RECORDS, filter.redact,
4397 NotificationRecordProto.SNOOZED);
Julia Reynolds520df6e2017-02-13 09:05:10 -05004398 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004399
Kweku Adams93304b62017-09-20 17:03:00 -07004400 long zenLog = proto.start(NotificationServiceDumpProto.ZEN);
4401 mZenModeHelper.dump(proto);
4402 for (ComponentName suppressor : mEffectsSuppressors) {
Kweku Adams99546332018-01-24 17:03:50 -08004403 suppressor.writeToProto(proto, ZenModeProto.SUPPRESSORS);
Kweku Adams93304b62017-09-20 17:03:00 -07004404 }
4405 proto.end(zenLog);
4406
4407 long listenersToken = proto.start(NotificationServiceDumpProto.NOTIFICATION_LISTENERS);
4408 mListeners.dump(proto, filter);
4409 proto.end(listenersToken);
4410
4411 proto.write(NotificationServiceDumpProto.LISTENER_HINTS, mListenerHints);
4412
4413 for (int i = 0; i < mListenersDisablingEffects.size(); ++i) {
4414 long effectsToken = proto.start(
4415 NotificationServiceDumpProto.LISTENERS_DISABLING_EFFECTS);
4416
4417 proto.write(
4418 ListenersDisablingEffectsProto.HINT, mListenersDisablingEffects.keyAt(i));
Julia Reynolds4703bac2018-09-12 10:39:30 -04004419 final ArraySet<ComponentName> listeners =
Kweku Adams93304b62017-09-20 17:03:00 -07004420 mListenersDisablingEffects.valueAt(i);
4421 for (int j = 0; j < listeners.size(); j++) {
Kweku Adamsf2169532018-12-20 04:15:49 -08004422 final ComponentName componentName = listeners.valueAt(j);
Julia Reynolds4703bac2018-09-12 10:39:30 -04004423 componentName.writeToProto(proto,
4424 ListenersDisablingEffectsProto.LISTENER_COMPONENTS);
Kweku Adams93304b62017-09-20 17:03:00 -07004425 }
4426
4427 proto.end(effectsToken);
4428 }
4429
4430 long assistantsToken = proto.start(
4431 NotificationServiceDumpProto.NOTIFICATION_ASSISTANTS);
4432 mAssistants.dump(proto, filter);
4433 proto.end(assistantsToken);
4434
4435 long conditionsToken = proto.start(NotificationServiceDumpProto.CONDITION_PROVIDERS);
4436 mConditionProviders.dump(proto, filter);
4437 proto.end(conditionsToken);
Kweku Adams62b42242017-09-25 12:54:02 -07004438
4439 long rankingToken = proto.start(NotificationServiceDumpProto.RANKING_CONFIG);
4440 mRankingHelper.dump(proto, filter);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004441 mPreferencesHelper.dump(proto, filter);
Kweku Adams62b42242017-09-25 12:54:02 -07004442 proto.end(rankingToken);
Julia Reynolds520df6e2017-02-13 09:05:10 -05004443 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004444
Julia Reynoldsc9842c12017-02-07 12:46:41 -05004445 proto.flush();
4446 }
4447
Vishnu Naire3e4d252018-03-01 11:26:57 -08004448 private void dumpNotificationRecords(PrintWriter pw, @NonNull DumpFilter filter) {
4449 synchronized (mNotificationLock) {
4450 int N;
4451 N = mNotificationList.size();
4452 if (N > 0) {
4453 pw.println(" Notification List:");
4454 for (int i = 0; i < N; i++) {
4455 final NotificationRecord nr = mNotificationList.get(i);
4456 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4457 nr.dump(pw, " ", getContext(), filter.redact);
4458 }
4459 pw.println(" ");
4460 }
4461 }
4462 }
4463
Kweku Adams887f09c2017-11-13 17:12:20 -08004464 void dumpImpl(PrintWriter pw, @NonNull DumpFilter filter) {
John Spurlock25e2d242014-06-27 13:58:23 -04004465 pw.print("Current Notification Manager state");
Dan Sandlera1770312015-07-10 13:59:29 -04004466 if (filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04004467 pw.print(" (filtered to "); pw.print(filter); pw.print(")");
John Spurlock25e2d242014-06-27 13:58:23 -04004468 }
4469 pw.println(':');
Adam Lesinski182f73f2013-12-05 16:48:06 -08004470 int N;
Julia Reynoldse6b53e62015-07-31 09:25:10 -04004471 final boolean zenOnly = filter.filtered && filter.zen;
Adam Lesinski182f73f2013-12-05 16:48:06 -08004472
John Spurlock50806fc2014-07-15 10:22:02 -04004473 if (!zenOnly) {
4474 synchronized (mToastQueue) {
4475 N = mToastQueue.size();
4476 if (N > 0) {
4477 pw.println(" Toast Queue:");
4478 for (int i=0; i<N; i++) {
4479 mToastQueue.get(i).dump(pw, " ", filter);
4480 }
4481 pw.println(" ");
Adam Lesinski182f73f2013-12-05 16:48:06 -08004482 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004483 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004484 }
4485
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004486 synchronized (mNotificationLock) {
John Spurlock50806fc2014-07-15 10:22:02 -04004487 if (!zenOnly) {
Vishnu Naire3e4d252018-03-01 11:26:57 -08004488 // Priority filters are only set when called via bugreport. If set
4489 // skip sections that are part of the critical section.
4490 if (!filter.normalPriority) {
4491 dumpNotificationRecords(pw, filter);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004492 }
Julia Reynoldse6b53e62015-07-31 09:25:10 -04004493 if (!filter.filtered) {
John Spurlock50806fc2014-07-15 10:22:02 -04004494 N = mLights.size();
4495 if (N > 0) {
4496 pw.println(" Lights List:");
4497 for (int i=0; i<N; i++) {
Chris Wren6054e612014-11-25 17:16:46 -05004498 if (i == N - 1) {
4499 pw.print(" > ");
4500 } else {
4501 pw.print(" ");
4502 }
4503 pw.println(mLights.get(i));
John Spurlock50806fc2014-07-15 10:22:02 -04004504 }
4505 pw.println(" ");
4506 }
John Spurlockcb566aa2014-08-03 22:58:28 -04004507 pw.println(" mUseAttentionLight=" + mUseAttentionLight);
Julia Reynolds28149f62018-07-03 10:43:35 -04004508 pw.println(" mHasLight=" + mHasLight);
John Spurlockcb566aa2014-08-03 22:58:28 -04004509 pw.println(" mNotificationPulseEnabled=" + mNotificationPulseEnabled);
Chris Wren6054e612014-11-25 17:16:46 -05004510 pw.println(" mSoundNotificationKey=" + mSoundNotificationKey);
4511 pw.println(" mVibrateNotificationKey=" + mVibrateNotificationKey);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004512 pw.println(" mDisableNotificationEffects=" + mDisableNotificationEffects);
John Spurlock32fe4c62014-10-02 12:16:02 -04004513 pw.println(" mCallState=" + callStateToString(mCallState));
John Spurlock50806fc2014-07-15 10:22:02 -04004514 pw.println(" mSystemReady=" + mSystemReady);
Chris Wren763a9bb2016-05-31 17:14:12 -04004515 pw.println(" mMaxPackageEnqueueRate=" + mMaxPackageEnqueueRate);
John Spurlock50806fc2014-07-15 10:22:02 -04004516 }
4517 pw.println(" mArchive=" + mArchive.toString());
4518 Iterator<StatusBarNotification> iter = mArchive.descendingIterator();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004519 int j=0;
John Spurlock50806fc2014-07-15 10:22:02 -04004520 while (iter.hasNext()) {
4521 final StatusBarNotification sbn = iter.next();
4522 if (filter != null && !filter.matches(sbn)) continue;
4523 pw.println(" " + sbn);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05004524 if (++j >= 5) {
John Spurlock50806fc2014-07-15 10:22:02 -04004525 if (iter.hasNext()) pw.println(" ...");
4526 break;
4527 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004528 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004529
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004530 if (!zenOnly) {
4531 N = mEnqueuedNotifications.size();
4532 if (N > 0) {
4533 pw.println(" Enqueued Notification List:");
4534 for (int i = 0; i < N; i++) {
4535 final NotificationRecord nr = mEnqueuedNotifications.get(i);
4536 if (filter.filtered && !filter.matches(nr.sbn)) continue;
4537 nr.dump(pw, " ", getContext(), filter.redact);
4538 }
4539 pw.println(" ");
4540 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004541
4542 mSnoozeHelper.dump(pw, filter);
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05004543 }
4544 }
4545
John Spurlock50806fc2014-07-15 10:22:02 -04004546 if (!zenOnly) {
John Spurlock50806fc2014-07-15 10:22:02 -04004547 pw.println("\n Ranking Config:");
4548 mRankingHelper.dump(pw, " ", filter);
Chris Wren54bbef42014-07-09 18:37:56 -04004549
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004550 pw.println("\n Notification Preferences:");
4551 mPreferencesHelper.dump(pw, " ", filter);
4552
John Spurlock50806fc2014-07-15 10:22:02 -04004553 pw.println("\n Notification listeners:");
4554 mListeners.dump(pw, filter);
John Spurlockd8afe3c2014-08-01 14:04:07 -04004555 pw.print(" mListenerHints: "); pw.println(mListenerHints);
4556 pw.print(" mListenersDisablingEffects: (");
4557 N = mListenersDisablingEffects.size();
John Spurlock1fa865f2014-07-21 14:56:39 -04004558 for (int i = 0; i < N; i++) {
Bryce Lee7219ada2016-04-08 10:54:23 -07004559 final int hint = mListenersDisablingEffects.keyAt(i);
4560 if (i > 0) pw.print(';');
4561 pw.print("hint[" + hint + "]:");
4562
Julia Reynolds4703bac2018-09-12 10:39:30 -04004563 final ArraySet<ComponentName> listeners = mListenersDisablingEffects.valueAt(i);
Bryce Lee7219ada2016-04-08 10:54:23 -07004564 final int listenerSize = listeners.size();
4565
4566 for (int j = 0; j < listenerSize; j++) {
Kweku Adamsf2169532018-12-20 04:15:49 -08004567 if (j > 0) pw.print(',');
4568 final ComponentName listener = listeners.valueAt(j);
Julia Reynolds1f580572018-04-27 14:48:36 -04004569 if (listener != null) {
Julia Reynolds4703bac2018-09-12 10:39:30 -04004570 pw.print(listener);
Julia Reynolds1f580572018-04-27 14:48:36 -04004571 }
Bryce Lee7219ada2016-04-08 10:54:23 -07004572 }
John Spurlock1fa865f2014-07-21 14:56:39 -04004573 }
4574 pw.println(')');
Julia Reynolds77b2cc92016-11-08 14:41:09 -05004575 pw.println("\n Notification assistant services:");
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04004576 mAssistants.dump(pw, filter);
John Spurlock50806fc2014-07-15 10:22:02 -04004577 }
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004578
Julia Reynolds520df6e2017-02-13 09:05:10 -05004579 if (!filter.filtered || zenOnly) {
4580 pw.println("\n Zen Mode:");
4581 pw.print(" mInterruptionFilter="); pw.println(mInterruptionFilter);
4582 mZenModeHelper.dump(pw, " ");
4583
4584 pw.println("\n Zen Log:");
4585 ZenLog.dump(pw, " ");
Julia Reynolds72f1cbb2016-09-19 14:57:31 -04004586 }
4587
John Spurlocke77bb362014-04-26 10:24:59 -04004588 pw.println("\n Condition providers:");
John Spurlock25e2d242014-06-27 13:58:23 -04004589 mConditionProviders.dump(pw, filter);
Christoph Studer265c1052014-07-23 17:14:33 +02004590
4591 pw.println("\n Group summaries:");
4592 for (Entry<String, NotificationRecord> entry : mSummaryByGroupKey.entrySet()) {
4593 NotificationRecord r = entry.getValue();
4594 pw.println(" " + entry.getKey() + " -> " + r.getKey());
4595 if (mNotificationsByKey.get(r.getKey()) != r) {
4596 pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey.");
Dan Sandlera1770312015-07-10 13:59:29 -04004597 r.dump(pw, " ", getContext(), filter.redact);
Christoph Studer265c1052014-07-23 17:14:33 +02004598 }
4599 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05004600
4601 if (!zenOnly) {
4602 pw.println("\n Usage Stats:");
4603 mUsageStats.dump(pw, " ", filter);
4604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 }
4606 }
4607
Adam Lesinski182f73f2013-12-05 16:48:06 -08004608 /**
4609 * The private API only accessible to the system process.
4610 */
4611 private final NotificationManagerInternal mInternalService = new NotificationManagerInternal() {
4612 @Override
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004613 public NotificationChannel getNotificationChannel(String pkg, int uid, String
4614 channelId) {
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004615 return mPreferencesHelper.getNotificationChannel(pkg, uid, channelId, false);
Julia Reynoldsf3de8aa2017-09-29 15:52:37 -04004616 }
4617
4618 @Override
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004619 public void enqueueNotification(String pkg, String opPkg, int callingUid, int callingPid,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004620 String tag, int id, Notification notification, int userId) {
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004621 enqueueNotificationInternal(pkg, opPkg, callingUid, callingPid, tag, id, notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004622 userId);
Adam Lesinski182f73f2013-12-05 16:48:06 -08004623 }
Christoph Studer365e4c32014-09-18 20:35:36 +02004624
4625 @Override
4626 public void removeForegroundServiceFlagFromNotification(String pkg, int notificationId,
4627 int userId) {
4628 checkCallerIsSystem();
Julia Reynolds564273f2018-09-13 15:53:11 -04004629 mHandler.post(() -> {
4630 synchronized (mNotificationLock) {
4631 // strip flag from all enqueued notifications. listeners will be informed
4632 // in post runnable.
4633 List<NotificationRecord> enqueued = findNotificationsByListLocked(
4634 mEnqueuedNotifications, pkg, null, notificationId, userId);
4635 for (int i = 0; i < enqueued.size(); i++) {
4636 removeForegroundServiceFlagLocked(enqueued.get(i));
4637 }
4638
4639 // if posted notification exists, strip its flag and tell listeners
4640 NotificationRecord r = findNotificationByListLocked(
4641 mNotificationList, pkg, null, notificationId, userId);
4642 if (r != null) {
4643 removeForegroundServiceFlagLocked(r);
4644 mRankingHelper.sort(mNotificationList);
4645 mListeners.notifyPostedLocked(r, r);
Julia Reynolds8f488d32016-10-14 10:59:01 -04004646 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004647 }
4648 });
4649 }
4650
Julia Reynolds88860ce2017-06-01 16:55:49 -04004651 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04004652 private void removeForegroundServiceFlagLocked(NotificationRecord r) {
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004653 if (r == null) {
4654 return;
Christoph Studer365e4c32014-09-18 20:35:36 +02004655 }
Geoffrey Pitsch87237d72017-04-13 13:44:09 -04004656 StatusBarNotification sbn = r.sbn;
4657 // NoMan adds flags FLAG_NO_CLEAR and FLAG_ONGOING_EVENT when it sees
4658 // FLAG_FOREGROUND_SERVICE. Hence it's not enough to remove
4659 // FLAG_FOREGROUND_SERVICE, we have to revert to the flags we received
4660 // initially *and* force remove FLAG_FOREGROUND_SERVICE.
4661 sbn.getNotification().flags =
Julia Reynoldse5c60452018-04-30 14:41:36 -04004662 (r.mOriginalFlags & ~FLAG_FOREGROUND_SERVICE);
Christoph Studer365e4c32014-09-18 20:35:36 +02004663 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08004664 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004665
Christoph Studer8fd7f1e2014-04-11 17:35:05 -04004666 void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
Scott Greenwald9b05c612013-06-25 23:44:05 -04004667 final int callingPid, final String tag, final int id, final Notification notification,
Julia Reynoldsfea6f7b2017-04-19 13:50:12 -04004668 int incomingUserId) {
Daniel Sandler0da673f2012-04-11 12:33:16 -04004669 if (DBG) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08004670 Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id
4671 + " notification=" + notification);
Daniel Sandler0da673f2012-04-11 12:33:16 -04004672 }
Dianne Hackborn41203752012-08-31 14:05:51 -07004673
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004674 if (pkg == null || notification == null) {
4675 throw new IllegalArgumentException("null not allowed: pkg=" + pkg
4676 + " id=" + id + " notification=" + notification);
4677 }
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004678
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004679 final int userId = ActivityManager.handleIncomingUser(callingPid,
4680 callingUid, incomingUserId, true, false, "enqueueNotification", pkg);
4681 final UserHandle user = UserHandle.of(userId);
4682
4683 // Can throw a SecurityException if the calling uid doesn't have permission to post
4684 // as "pkg"
4685 final int notificationUid = resolveNotificationUid(opPkg, pkg, callingUid, userId);
4686
4687 checkRestrictedCategories(notification);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004688
Julia Reynoldse46bb372016-03-17 11:05:58 -04004689 // Fix the notification as best we can.
4690 try {
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004691 fixNotification(notification, pkg, userId);
Julia Reynolds4db59552017-06-30 13:34:01 -04004692
Julia Reynoldse46bb372016-03-17 11:05:58 -04004693 } catch (NameNotFoundException e) {
4694 Slog.e(TAG, "Cannot create a context for sending app", e);
4695 return;
4696 }
4697
Chris Wren888b7a82016-06-17 15:47:19 -04004698 mUsageStats.registerEnqueuedByApp(pkg);
4699
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004700 // setup local book-keeping
Julia Reynoldsbad42972017-04-25 13:52:49 -04004701 String channelId = notification.getChannelId();
4702 if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
4703 channelId = (new Notification.TvExtender(notification)).getChannelId();
Julia Reynolds5f20e9f2017-01-30 08:54:53 -05004704 }
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004705 final NotificationChannel channel = mPreferencesHelper.getNotificationChannel(pkg,
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004706 notificationUid, channelId, false /* includeDeleted */);
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004707 if (channel == null) {
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004708 final String noChannelStr = "No Channel found for "
4709 + "pkg=" + pkg
4710 + ", channelId=" + channelId
Julia Reynoldsf26eb912017-05-22 15:47:06 -04004711 + ", id=" + id
4712 + ", tag=" + tag
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004713 + ", opPkg=" + opPkg
4714 + ", callingUid=" + callingUid
4715 + ", userId=" + userId
4716 + ", incomingUserId=" + incomingUserId
4717 + ", notificationUid=" + notificationUid
4718 + ", notification=" + notification;
Tony Mak180a9c42019-03-08 13:33:08 +00004719 Slog.e(TAG, noChannelStr);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004720 boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
Beverly5d4564b2018-04-10 20:09:23 -04004721 == NotificationManager.IMPORTANCE_NONE;
4722
4723 if (!appNotificationsOff) {
4724 doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
4725 "Failed to post notification on channel \"" + channelId + "\"\n" +
4726 "See log for more details");
4727 }
Geoffrey Pitsch96cac7f2017-03-23 17:57:12 -04004728 return;
Geoffrey Pitsch1f17e022017-01-03 16:44:20 -05004729 }
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004730
Chris Wrena61f1792016-08-04 11:24:42 -04004731 final StatusBarNotification n = new StatusBarNotification(
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004732 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
Julia Reynolds423b9fc2016-11-09 09:51:08 -05004733 user, null, System.currentTimeMillis());
Geoffrey Pitscha22f6442017-05-05 16:47:38 +00004734 final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
Aaron Heuckrothe5bec152018-07-09 16:26:09 -04004735 r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
Chris Wrena61f1792016-08-04 11:24:42 -04004736
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004737 if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
4738 final boolean fgServiceShown = channel.isFgServiceShown();
4739 if (((channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
4740 || !fgServiceShown)
4741 && (r.getImportance() == IMPORTANCE_MIN
4742 || r.getImportance() == IMPORTANCE_NONE)) {
4743 // Increase the importance of foreground service notifications unless the user had
4744 // an opinion otherwise (and the channel hasn't yet shown a fg service).
4745 if (TextUtils.isEmpty(channelId)
4746 || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004747 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004748 } else {
4749 channel.setImportance(IMPORTANCE_LOW);
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004750 r.setSystemImportance(IMPORTANCE_LOW);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004751 if (!fgServiceShown) {
4752 channel.unlockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
4753 channel.setFgServiceShown(true);
4754 }
Julia Reynoldsefcdff42018-08-09 09:42:56 -04004755 mPreferencesHelper.updateNotificationChannel(
4756 pkg, notificationUid, channel, false);
Dianne Hackborn025d4a52018-04-30 16:23:26 -07004757 r.updateNotificationChannel(channel);
4758 }
4759 } else if (!fgServiceShown && !TextUtils.isEmpty(channelId)
4760 && !NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
4761 channel.setFgServiceShown(true);
Julia Reynolds8617e4e2017-09-18 16:52:37 -04004762 r.updateNotificationChannel(channel);
4763 }
4764 }
4765
Julia Reynolds5e702192017-08-18 09:22:40 -04004766 if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
4767 r.sbn.getOverrideGroupKey() != null)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004768 return;
Joe Onoratobd73d012010-06-04 11:44:54 -07004769 }
4770
Felipe Lemedd85da62016-06-28 11:29:54 -07004771 // Whitelist pending intents.
4772 if (notification.allPendingIntents != null) {
4773 final int intentCount = notification.allPendingIntents.size();
4774 if (intentCount > 0) {
4775 final ActivityManagerInternal am = LocalServices
4776 .getService(ActivityManagerInternal.class);
4777 final long duration = LocalServices.getService(
4778 DeviceIdleController.LocalService.class).getNotificationWhitelistDuration();
4779 for (int i = 0; i < intentCount; i++) {
4780 PendingIntent pendingIntent = notification.allPendingIntents.valueAt(i);
4781 if (pendingIntent != null) {
Dianne Hackborn98305522017-05-05 17:53:53 -07004782 am.setPendingIntentWhitelistDuration(pendingIntent.getTarget(),
4783 WHITELIST_TOKEN, duration);
Michal Karpinskiac116df2018-12-10 17:51:42 +00004784 am.setPendingIntentAllowBgActivityStarts(pendingIntent.getTarget(),
Michal Karpinskic8aa91b2019-01-10 16:45:59 +00004785 WHITELIST_TOKEN, (FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER
4786 | FLAG_SERVICE_SENDER));
Felipe Lemedd85da62016-06-28 11:29:54 -07004787 }
4788 }
4789 }
4790 }
Felipe Lemea1b79bf2016-05-24 13:06:54 -07004791
Chris Wren47633422016-01-22 09:56:59 -05004792 mHandler.post(new EnqueueNotificationRunnable(userId, r));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 }
4794
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004795 @VisibleForTesting
4796 protected void fixNotification(Notification notification, String pkg, int userId)
4797 throws NameNotFoundException {
4798 final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
4799 pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
4800 (userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
4801 Notification.addFieldsFromContext(ai, notification);
4802
4803 int canColorize = mPackageManagerClient.checkPermission(
4804 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, pkg);
4805 if (canColorize == PERMISSION_GRANTED) {
4806 notification.flags |= Notification.FLAG_CAN_COLORIZE;
4807 } else {
4808 notification.flags &= ~Notification.FLAG_CAN_COLORIZE;
4809 }
4810
Takamasa Kuramitsu3dd7b2d2018-12-14 20:46:02 +09004811 if (notification.fullScreenIntent != null && ai.targetSdkVersion >= Build.VERSION_CODES.Q) {
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004812 int fullscreenIntentPermission = mPackageManagerClient.checkPermission(
4813 android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
4814 if (fullscreenIntentPermission != PERMISSION_GRANTED) {
4815 notification.fullScreenIntent = null;
Tony Mak180a9c42019-03-08 13:33:08 +00004816 Slog.w(TAG, "Package " + pkg +
Julia Reynolds47fd15f2018-11-28 10:16:00 -05004817 ": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
4818 }
4819 }
4820 }
4821
Mady Mellor7eb18ef2019-03-27 14:03:46 -07004822 /**
4823 * Updates the flags for this notification to reflect whether it is a bubble or not.
4824 */
Mady Mellorbe797962019-04-01 16:04:24 -07004825 private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId,
4826 NotificationRecord oldRecord) {
Mady Mellor7eb18ef2019-03-27 14:03:46 -07004827 Notification notification = r.getNotification();
Mady Mellora54e9fa2019-04-18 13:26:18 -07004828 if (isNotificationAppropriateToBubble(r, pkg, userId, oldRecord)) {
4829 notification.flags |= FLAG_BUBBLE;
4830 } else {
4831 notification.flags &= ~FLAG_BUBBLE;
4832 }
4833 }
4834
4835 /**
4836 * @return whether the provided notification record is allowed to be represented as a bubble.
4837 */
4838 private boolean isNotificationAppropriateToBubble(NotificationRecord r, String pkg, int userId,
4839 NotificationRecord oldRecord) {
4840 Notification notification = r.getNotification();
Mady Mellorca0c24c2019-05-16 16:14:32 -07004841 Notification.BubbleMetadata metadata = notification.getBubbleMetadata();
4842 boolean intentCanBubble = metadata != null
4843 && canLaunchInActivityView(getContext(), metadata.getIntent(), pkg);
Mady Mellorbe797962019-04-01 16:04:24 -07004844
Mady Mellor5c11a2e2019-04-25 17:26:15 -07004845 // Does the app want to bubble & is able to bubble
Mady Mellorca0c24c2019-05-16 16:14:32 -07004846 boolean canBubble = intentCanBubble
Mady Mellorbe797962019-04-01 16:04:24 -07004847 && mPreferencesHelper.areBubblesAllowed(pkg, userId)
Mady Mellorc6820342019-05-20 12:04:36 -07004848 && mPreferencesHelper.bubblesEnabled(r.sbn.getUser())
Mady Mellor5c11a2e2019-04-25 17:26:15 -07004849 && r.getChannel().canBubble()
4850 && !mActivityManager.isLowRamDevice();
Mady Mellorbe797962019-04-01 16:04:24 -07004851
4852 // Is the app in the foreground?
4853 final boolean appIsForeground =
4854 mActivityManager.getPackageImportance(pkg) == IMPORTANCE_FOREGROUND;
4855
4856 // Is the notification something we'd allow to bubble?
4857 // A call with a foreground service + person
4858 ArrayList<Person> peopleList = notification.extras != null
4859 ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
4860 : null;
4861 boolean isForegroundCall = CATEGORY_CALL.equals(notification.category)
4862 && (notification.flags & FLAG_FOREGROUND_SERVICE) != 0;
Mady Mellora10448e2019-04-26 13:50:58 -07004863 // OR message style (which always has a person) with any remote input
Mady Mellorbe797962019-04-01 16:04:24 -07004864 Class<? extends Notification.Style> style = notification.getNotificationStyle();
4865 boolean isMessageStyle = Notification.MessagingStyle.class.equals(style);
Mady Mellora10448e2019-04-26 13:50:58 -07004866 boolean notificationAppropriateToBubble =
4867 (isMessageStyle && hasValidRemoteInput(notification))
Mady Mellorbe797962019-04-01 16:04:24 -07004868 || (peopleList != null && !peopleList.isEmpty() && isForegroundCall);
Mady Mellora10448e2019-04-26 13:50:58 -07004869
Mady Mellorbe797962019-04-01 16:04:24 -07004870 // OR something that was previously a bubble & still exists
4871 boolean bubbleUpdate = oldRecord != null
4872 && (oldRecord.getNotification().flags & FLAG_BUBBLE) != 0;
Mady Mellora54e9fa2019-04-18 13:26:18 -07004873 return canBubble && (notificationAppropriateToBubble || appIsForeground || bubbleUpdate);
Mady Mellor7eb18ef2019-03-27 14:03:46 -07004874 }
4875
Mady Mellora10448e2019-04-26 13:50:58 -07004876 private boolean hasValidRemoteInput(Notification n) {
4877 // Also check for inline reply
4878 Notification.Action[] actions = n.actions;
4879 if (actions != null) {
4880 // Get the remote inputs
4881 for (int i = 0; i < actions.length; i++) {
4882 Notification.Action action = actions[i];
4883 RemoteInput[] inputs = action.getRemoteInputs();
4884 if (inputs != null && inputs.length > 0) {
4885 return true;
4886 }
4887 }
4888 }
4889 return false;
4890 }
4891
Mady Mellorca0c24c2019-05-16 16:14:32 -07004892 /**
4893 * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
4894 *
4895 * @param context the context to use.
4896 * @param pendingIntent the pending intent of the bubble.
4897 * @param packageName the notification package name for this bubble.
4898 */
4899 // Keep checks in sync with BubbleController#canLaunchInActivityView.
4900 @VisibleForTesting
4901 protected boolean canLaunchInActivityView(Context context, PendingIntent pendingIntent,
4902 String packageName) {
4903 if (pendingIntent == null) {
4904 Log.w(TAG, "Unable to create bubble -- no intent");
4905 return false;
4906 }
4907
4908 // Need escalated privileges to get the intent.
4909 final long token = Binder.clearCallingIdentity();
4910 Intent intent;
4911 try {
4912 intent = pendingIntent.getIntent();
4913 } finally {
4914 Binder.restoreCallingIdentity(token);
4915 }
4916
4917 ActivityInfo info = intent != null
4918 ? intent.resolveActivityInfo(context.getPackageManager(), 0)
4919 : null;
4920 if (info == null) {
4921 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4922 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
4923 Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
4924 + intent);
4925 return false;
4926 }
4927 if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
4928 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4929 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
4930 Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
4931 + intent);
4932 return false;
4933 }
4934 if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
4935 StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
4936 BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
4937 Log.w(TAG, "Unable to send as bubble -- activity is not documentLaunchMode=always "
4938 + "for intent: " + intent);
4939 return false;
4940 }
4941 if ((info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) {
4942 Log.w(TAG, "Unable to send as bubble -- activity is not embeddable for intent: "
4943 + intent);
4944 return false;
4945 }
4946 return true;
4947 }
4948
Geoffrey Pitsch4c6eef22017-04-19 10:26:45 -04004949 private void doChannelWarningToast(CharSequence toastText) {
Julia Reynoldsbba26b12018-10-11 09:21:11 -04004950 Binder.withCleanCallingIdentity(() -> {
4951 final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
4952 final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
4953 Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
4954 if (warningEnabled) {
4955 Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
4956 Toast.LENGTH_SHORT);
4957 toast.show();
4958 }
4959 });
Geoffrey Pitsch86c11e602017-04-17 15:28:40 -04004960 }
4961
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004962 @VisibleForTesting
4963 int resolveNotificationUid(String callingPkg, String targetPkg,
4964 int callingUid, int userId) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04004965 if (userId == UserHandle.USER_ALL) {
4966 userId = USER_SYSTEM;
4967 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004968 // posted from app A on behalf of app A
Julia Reynoldsb6634872018-09-25 13:19:53 -04004969 if (isCallerSameApp(targetPkg, callingUid, userId)
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004970 && (TextUtils.equals(callingPkg, targetPkg)
4971 || isCallerSameApp(callingPkg, callingUid, userId))) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004972 return callingUid;
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004973 }
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04004974
4975 int targetUid = -1;
4976 try {
4977 targetUid = mPackageManagerClient.getPackageUidAsUser(targetPkg, userId);
4978 } catch (NameNotFoundException e) {
4979 /* ignore */
4980 }
4981 // posted from app A on behalf of app B
4982 if (targetUid != -1 && (isCallerAndroid(callingPkg, callingUid)
4983 || mPreferencesHelper.isDelegateAllowed(
4984 targetPkg, targetUid, callingPkg, callingUid))) {
4985 return targetUid;
4986 }
4987
Julia Reynoldsecc1b572018-10-01 16:19:24 -04004988 throw new SecurityException("Caller " + callingPkg + ":" + callingUid
4989 + " cannot post for pkg " + targetPkg + " in user " + userId);
Svetoslav Ganov2a67ee82017-02-16 18:57:57 -08004990 }
4991
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004992 /**
4993 * Checks if a notification can be posted. checks rate limiter, snooze helper, and blocking.
4994 *
4995 * Has side effects.
4996 */
Julia Reynolds268647a2018-10-25 16:54:27 -04004997 private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
Julia Reynolds5e702192017-08-18 09:22:40 -04004998 NotificationRecord r, boolean isAutogroup) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05004999 final String pkg = r.sbn.getPackageName();
Geoffrey Pitsch27684152017-05-02 11:41:31 -04005000 final boolean isSystemNotification =
Julia Reynolds268647a2018-10-25 16:54:27 -04005001 isUidSystemOrPhone(uid) || ("android".equals(pkg));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005002 final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
5003
5004 // Limit the number of notifications that any given package except the android
5005 // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
5006 if (!isSystemNotification && !isNotificationFromListener) {
5007 synchronized (mNotificationLock) {
Julia Reynolds268647a2018-10-25 16:54:27 -04005008 final int callingUid = Binder.getCallingUid();
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005009 if (mNotificationsByKey.get(r.sbn.getKey()) == null
Julia Reynolds268647a2018-10-25 16:54:27 -04005010 && isCallerInstantApp(callingUid, userId)) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04005011 // Ephemeral apps have some special constraints for notifications.
5012 // They are not allowed to create new notifications however they are allowed to
5013 // update notifications created by the system (e.g. a foreground service
5014 // notification).
5015 throw new SecurityException("Instant app " + pkg
5016 + " cannot create notifications");
5017 }
5018
5019 // rate limit updates that aren't completed progress notifications
5020 if (mNotificationsByKey.get(r.sbn.getKey()) != null
Julia Reynolds5e702192017-08-18 09:22:40 -04005021 && !r.getNotification().hasCompletedProgress()
5022 && !isAutogroup) {
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04005023
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005024 final float appEnqueueRate = mUsageStats.getAppEnqueueRate(pkg);
5025 if (appEnqueueRate > mMaxPackageEnqueueRate) {
5026 mUsageStats.registerOverRateQuota(pkg);
5027 final long now = SystemClock.elapsedRealtime();
5028 if ((now - mLastOverRateLogTime) > MIN_PACKAGE_OVERRATE_LOG_INTERVAL) {
5029 Slog.e(TAG, "Package enqueue rate is " + appEnqueueRate
Julia Reynolds5e702192017-08-18 09:22:40 -04005030 + ". Shedding " + r.sbn.getKey() + ". package=" + pkg);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005031 mLastOverRateLogTime = now;
5032 }
5033 return false;
5034 }
5035 }
5036
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04005037 // limit the number of outstanding notificationrecords an app can have
5038 int count = getNotificationCountLocked(pkg, userId, id, tag);
5039 if (count >= MAX_PACKAGE_NOTIFICATIONS) {
5040 mUsageStats.registerOverCountQuota(pkg);
5041 Slog.e(TAG, "Package has already posted or enqueued " + count
5042 + " notifications. Not showing more. package=" + pkg);
5043 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005044 }
5045 }
5046 }
5047
5048 // snoozed apps
5049 if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
Julia Reynolds520df6e2017-02-13 09:05:10 -05005050 MetricsLogger.action(r.getLogMaker()
5051 .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
5052 .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005053 if (DBG) {
5054 Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
5055 }
5056 mSnoozeHelper.update(userId, r);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05005057 handleSavePolicyFile();
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005058 return false;
5059 }
5060
5061
5062 // blocked apps
5063 if (isBlocked(r, mUsageStats)) {
5064 return false;
5065 }
5066
5067 return true;
5068 }
5069
Andreas Gampea36dc622018-02-05 17:19:22 -08005070 @GuardedBy("mNotificationLock")
Julia Reynolds6ad0aec2017-07-05 08:47:03 -04005071 protected int getNotificationCountLocked(String pkg, int userId, int excludedId,
5072 String excludedTag) {
5073 int count = 0;
5074 final int N = mNotificationList.size();
5075 for (int i = 0; i < N; i++) {
5076 final NotificationRecord existing = mNotificationList.get(i);
5077 if (existing.sbn.getPackageName().equals(pkg)
5078 && existing.sbn.getUserId() == userId) {
5079 if (existing.sbn.getId() == excludedId
5080 && TextUtils.equals(existing.sbn.getTag(), excludedTag)) {
5081 continue;
5082 }
5083 count++;
5084 }
5085 }
5086 final int M = mEnqueuedNotifications.size();
5087 for (int i = 0; i < M; i++) {
5088 final NotificationRecord existing = mEnqueuedNotifications.get(i);
5089 if (existing.sbn.getPackageName().equals(pkg)
5090 && existing.sbn.getUserId() == userId) {
5091 count++;
5092 }
5093 }
5094 return count;
5095 }
5096
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005097 protected boolean isBlocked(NotificationRecord r, NotificationUsageStats usageStats) {
Beverly3c707b42018-09-14 09:49:07 -04005098 if (isBlocked(r)) {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005099 Slog.e(TAG, "Suppressing notification from package by user request.");
5100 usageStats.registerBlocked(r);
Beverly3c707b42018-09-14 09:49:07 -04005101 return true;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005102 }
Beverly3c707b42018-09-14 09:49:07 -04005103 return false;
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005104 }
5105
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005106 private boolean isBlocked(NotificationRecord r) {
5107 final String pkg = r.sbn.getPackageName();
5108 final int callingUid = r.sbn.getUid();
5109 return mPreferencesHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
5110 || mPreferencesHelper.getImportance(pkg, callingUid)
5111 == NotificationManager.IMPORTANCE_NONE
5112 || r.getImportance() == NotificationManager.IMPORTANCE_NONE;
5113 }
5114
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005115 protected class SnoozeNotificationRunnable implements Runnable {
5116 private final String mKey;
5117 private final long mDuration;
5118 private final String mSnoozeCriterionId;
5119
5120 SnoozeNotificationRunnable(String key, long duration, String snoozeCriterionId) {
5121 mKey = key;
5122 mDuration = duration;
5123 mSnoozeCriterionId = snoozeCriterionId;
5124 }
5125
5126 @Override
5127 public void run() {
5128 synchronized (mNotificationLock) {
5129 final NotificationRecord r = findNotificationByKeyLocked(mKey);
5130 if (r != null) {
5131 snoozeLocked(r);
5132 }
5133 }
5134 }
5135
Julia Reynolds88860ce2017-06-01 16:55:49 -04005136 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005137 void snoozeLocked(NotificationRecord r) {
5138 if (r.sbn.isGroup()) {
5139 final List<NotificationRecord> groupNotifications = findGroupNotificationsLocked(
5140 r.sbn.getPackageName(), r.sbn.getGroupKey(), r.sbn.getUserId());
5141 if (r.getNotification().isGroupSummary()) {
5142 // snooze summary and all children
5143 for (int i = 0; i < groupNotifications.size(); i++) {
5144 snoozeNotificationLocked(groupNotifications.get(i));
5145 }
5146 } else {
5147 // if there is a valid summary for this group, and we are snoozing the only
5148 // child, also snooze the summary
5149 if (mSummaryByGroupKey.containsKey(r.sbn.getGroupKey())) {
5150 if (groupNotifications.size() != 2) {
5151 snoozeNotificationLocked(r);
5152 } else {
5153 // snooze summary and the one child
5154 for (int i = 0; i < groupNotifications.size(); i++) {
5155 snoozeNotificationLocked(groupNotifications.get(i));
5156 }
5157 }
5158 } else {
5159 snoozeNotificationLocked(r);
5160 }
5161 }
5162 } else {
5163 // just snooze the one notification
5164 snoozeNotificationLocked(r);
5165 }
5166 }
5167
Julia Reynolds88860ce2017-06-01 16:55:49 -04005168 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005169 void snoozeNotificationLocked(NotificationRecord r) {
5170 MetricsLogger.action(r.getLogMaker()
5171 .setCategory(MetricsEvent.NOTIFICATION_SNOOZED)
5172 .setType(MetricsEvent.TYPE_CLOSE)
Chris Wren21a2e722017-10-02 17:44:53 -04005173 .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_SNOOZE_DURATION_MS,
5174 mDuration)
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005175 .addTaggedData(MetricsEvent.NOTIFICATION_SNOOZED_CRITERIA,
5176 mSnoozeCriterionId == null ? 0 : 1));
Esteban Talavera5d603892018-11-15 10:55:24 +00005177 reportUserInteraction(r);
Julia Reynolds0839c022017-06-15 15:24:01 -04005178 boolean wasPosted = removeFromNotificationListsLocked(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04005179 cancelNotificationLocked(r, false, REASON_SNOOZED, wasPosted, null);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005180 updateLightsLocked();
5181 if (mSnoozeCriterionId != null) {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005182 mAssistants.notifyAssistantSnoozedLocked(r.sbn, mSnoozeCriterionId);
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005183 mSnoozeHelper.snooze(r);
5184 } else {
5185 mSnoozeHelper.snooze(r, mDuration);
5186 }
Julia Reynolds503ed942017-10-04 16:04:56 -04005187 r.recordSnoozed();
Julia Reynoldsb62dad42018-11-26 16:33:02 -05005188 handleSavePolicyFile();
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005189 }
5190 }
5191
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005192 protected class CancelNotificationRunnable implements Runnable {
5193 private final int mCallingUid;
5194 private final int mCallingPid;
5195 private final String mPkg;
5196 private final String mTag;
5197 private final int mId;
5198 private final int mMustHaveFlags;
5199 private final int mMustNotHaveFlags;
5200 private final boolean mSendDelete;
5201 private final int mUserId;
5202 private final int mReason;
5203 private final int mRank;
5204 private final int mCount;
5205 private final ManagedServiceInfo mListener;
5206
5207 CancelNotificationRunnable(final int callingUid, final int callingPid,
5208 final String pkg, final String tag, final int id,
5209 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
5210 final int userId, final int reason, int rank, int count,
5211 final ManagedServiceInfo listener) {
5212 this.mCallingUid = callingUid;
5213 this.mCallingPid = callingPid;
5214 this.mPkg = pkg;
5215 this.mTag = tag;
5216 this.mId = id;
5217 this.mMustHaveFlags = mustHaveFlags;
5218 this.mMustNotHaveFlags = mustNotHaveFlags;
5219 this.mSendDelete = sendDelete;
5220 this.mUserId = userId;
5221 this.mReason = reason;
5222 this.mRank = rank;
5223 this.mCount = count;
5224 this.mListener = listener;
5225 }
5226
5227 @Override
5228 public void run() {
5229 String listenerName = mListener == null ? null : mListener.component.toShortString();
5230 if (DBG) {
5231 EventLogTags.writeNotificationCancel(mCallingUid, mCallingPid, mPkg, mId, mTag,
5232 mUserId, mMustHaveFlags, mMustNotHaveFlags, mReason, listenerName);
5233 }
5234
5235 synchronized (mNotificationLock) {
5236 // Look for the notification, searching both the posted and enqueued lists.
5237 NotificationRecord r = findNotificationLocked(mPkg, mTag, mId, mUserId);
5238 if (r != null) {
5239 // The notification was found, check if it should be removed.
5240
5241 // Ideally we'd do this in the caller of this method. However, that would
5242 // require the caller to also find the notification.
5243 if (mReason == REASON_CLICK) {
5244 mUsageStats.registerClickedByUser(r);
5245 }
5246
5247 if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) {
5248 return;
5249 }
5250 if ((r.getNotification().flags & mMustNotHaveFlags) != 0) {
5251 return;
5252 }
5253
5254 // Cancel the notification.
5255 boolean wasPosted = removeFromNotificationListsLocked(r);
5256 cancelNotificationLocked(
5257 r, mSendDelete, mReason, mRank, mCount, wasPosted, listenerName);
5258 cancelGroupChildrenLocked(r, mCallingUid, mCallingPid, listenerName,
5259 mSendDelete, null);
5260 updateLightsLocked();
5261 } else {
5262 // No notification was found, assume that it is snoozed and cancel it.
5263 if (mReason != REASON_SNOOZED) {
5264 final boolean wasSnoozed = mSnoozeHelper.cancel(mUserId, mPkg, mTag, mId);
5265 if (wasSnoozed) {
Julia Reynoldsb62dad42018-11-26 16:33:02 -05005266 handleSavePolicyFile();
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005267 }
5268 }
5269 }
5270 }
5271 }
5272 }
5273
Julia Reynoldsbaff4002016-12-15 11:34:26 -05005274 protected class EnqueueNotificationRunnable implements Runnable {
Chris Wren47633422016-01-22 09:56:59 -05005275 private final NotificationRecord r;
5276 private final int userId;
5277
5278 EnqueueNotificationRunnable(int userId, NotificationRecord r) {
5279 this.userId = userId;
5280 this.r = r;
5281 };
5282
5283 @Override
5284 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005285 synchronized (mNotificationLock) {
Julia Reynolds573c6532017-01-24 17:44:38 -05005286 mEnqueuedNotifications.add(r);
Julia Reynolds2a128742016-11-28 14:29:25 -05005287 scheduleTimeoutLocked(r);
Julia Reynolds573c6532017-01-24 17:44:38 -05005288
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005289 final StatusBarNotification n = r.sbn;
5290 if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
5291 NotificationRecord old = mNotificationsByKey.get(n.getKey());
5292 if (old != null) {
5293 // Retain ranking information from previous record
5294 r.copyRankingInformation(old);
5295 }
5296
5297 final int callingUid = n.getUid();
5298 final int callingPid = n.getInitialPid();
5299 final Notification notification = n.getNotification();
5300 final String pkg = n.getPackageName();
5301 final int id = n.getId();
5302 final String tag = n.getTag();
5303
Mady Mellor7eb18ef2019-03-27 14:03:46 -07005304 // We need to fix the notification up a little for bubbles
Mady Mellorbe797962019-04-01 16:04:24 -07005305 flagNotificationForBubbles(r, pkg, callingUid, old);
Mady Mellor7eb18ef2019-03-27 14:03:46 -07005306
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005307 // Handle grouped notifications and bail out early if we
5308 // can to avoid extracting signals.
5309 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
5310
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04005311 // if this is a group child, unsnooze parent summary
5312 if (n.isGroup() && notification.isGroupChild()) {
5313 mSnoozeHelper.repostGroupSummary(pkg, r.getUserId(), n.getGroupKey());
5314 }
5315
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005316 // This conditional is a dirty hack to limit the logging done on
5317 // behalf of the download manager without affecting other apps.
5318 if (!pkg.equals("com.android.providers.downloads")
5319 || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
5320 int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW;
Chris Wren6676dab2016-12-21 18:26:27 -05005321 if (old != null) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005322 enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE;
Chris Wren6676dab2016-12-21 18:26:27 -05005323 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005324 EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
5325 pkg, id, tag, userId, notification.toString(),
5326 enqueueStatus);
5327 }
Chris Wren6676dab2016-12-21 18:26:27 -05005328
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005329 // tell the assistant service about the notification
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04005330 if (mAssistants.isEnabled()) {
Tony Makeda84a72018-11-19 17:01:32 +00005331 mAssistants.onNotificationEnqueuedLocked(r);
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005332 mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005333 DELAY_FOR_ASSISTANT_TIME);
5334 } else {
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005335 mHandler.post(new PostNotificationRunnable(r.getKey()));
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005336 }
5337 }
5338 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005339 }
5340
Beverly5a20a5e2018-03-06 15:02:44 -05005341 @GuardedBy("mNotificationLock")
5342 private boolean isPackageSuspendedLocked(NotificationRecord r) {
5343 final String pkg = r.sbn.getPackageName();
5344 final int callingUid = r.sbn.getUid();
5345
5346 return isPackageSuspendedForUser(pkg, callingUid);
5347 }
5348
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005349 protected class PostNotificationRunnable implements Runnable {
5350 private final String key;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005351
Julia Reynoldsd94054f2017-02-01 11:11:06 -05005352 PostNotificationRunnable(String key) {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005353 this.key = key;
5354 }
5355
5356 @Override
5357 public void run() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005358 synchronized (mNotificationLock) {
5359 try {
5360 NotificationRecord r = null;
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005361 int N = mEnqueuedNotifications.size();
5362 for (int i = 0; i < N; i++) {
5363 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5364 if (Objects.equals(key, enqueued.getKey())) {
5365 r = enqueued;
5366 break;
Chris Wren6676dab2016-12-21 18:26:27 -05005367 }
Chris Wren6676dab2016-12-21 18:26:27 -05005368 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005369 if (r == null) {
5370 Slog.i(TAG, "Cannot find enqueued record for key: " + key);
5371 return;
5372 }
Beverly5a20a5e2018-03-06 15:02:44 -05005373
Julia Reynoldsefcdff42018-08-09 09:42:56 -04005374 if (isBlocked(r)) {
5375 Slog.i(TAG, "notification blocked by assistant request");
5376 return;
5377 }
5378
Beverly3c707b42018-09-14 09:49:07 -04005379 final boolean isPackageSuspended = isPackageSuspendedLocked(r);
5380 r.setHidden(isPackageSuspended);
5381 if (isPackageSuspended) {
5382 mUsageStats.registerSuspendedByAdmin(r);
5383 }
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005384 NotificationRecord old = mNotificationsByKey.get(key);
5385 final StatusBarNotification n = r.sbn;
5386 final Notification notification = n.getNotification();
Chris Wren6676dab2016-12-21 18:26:27 -05005387 int index = indexOfNotificationLocked(n.getKey());
5388 if (index < 0) {
5389 mNotificationList.add(r);
5390 mUsageStats.registerPostedByApp(r);
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005391 r.setInterruptive(isVisuallyInterruptive(null, r));
Chris Wren6676dab2016-12-21 18:26:27 -05005392 } else {
5393 old = mNotificationList.get(index);
5394 mNotificationList.set(index, r);
5395 mUsageStats.registerUpdatedByApp(r, old);
5396 // Make sure we don't lose the foreground service state.
5397 notification.flags |=
Julia Reynoldse5c60452018-04-30 14:41:36 -04005398 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
Chris Wren6676dab2016-12-21 18:26:27 -05005399 r.isUpdate = true;
Julia Reynoldsb3c68ff2018-05-22 14:58:39 -04005400 r.setTextChanged(isVisuallyInterruptive(old, r));
Chris Wren6676dab2016-12-21 18:26:27 -05005401 }
5402
5403 mNotificationsByKey.put(n.getKey(), r);
5404
5405 // Ensure if this is a foreground service that the proper additional
5406 // flags are set.
Julia Reynoldse5c60452018-04-30 14:41:36 -04005407 if ((notification.flags & FLAG_FOREGROUND_SERVICE) != 0) {
Mady Mellor49b1bf12019-03-29 12:00:02 -07005408 notification.flags |= FLAG_ONGOING_EVENT
5409 | FLAG_NO_CLEAR;
Chris Wren6676dab2016-12-21 18:26:27 -05005410 }
5411
Julia Reynolds27c0a962018-12-10 12:37:28 -05005412 mRankingHelper.extractSignals(r);
Chris Wren6676dab2016-12-21 18:26:27 -05005413 mRankingHelper.sort(mNotificationList);
5414
Gus Prevasa3226492018-10-23 11:10:09 -04005415 if (!r.isHidden()) {
5416 buzzBeepBlinkLocked(r);
5417 }
5418
Chris Wren6676dab2016-12-21 18:26:27 -05005419 if (notification.getSmallIcon() != null) {
5420 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06005421 mListeners.notifyPostedLocked(r, old);
Brad Stenningd2e7a972018-10-01 09:08:42 -07005422 if ((oldSbn == null || !Objects.equals(oldSbn.getGroup(), n.getGroup()))
5423 && !isCritical(r)) {
Julia Reynolds8aebf352017-06-26 11:35:33 -04005424 mHandler.post(new Runnable() {
5425 @Override
5426 public void run() {
Julia Reynoldsa13b3e22017-08-10 16:58:54 -04005427 mGroupHelper.onNotificationPosted(
5428 n, hasAutoGroupSummaryLocked(n));
Julia Reynolds8aebf352017-06-26 11:35:33 -04005429 }
5430 });
5431 }
Chris Wren6676dab2016-12-21 18:26:27 -05005432 } else {
5433 Slog.e(TAG, "Not posting notification without small icon: " + notification);
5434 if (old != null && !old.isCanceled) {
Beverly5a20a5e2018-03-06 15:02:44 -05005435 mListeners.notifyRemovedLocked(r,
Julia Reynolds3207e2f2018-12-20 09:39:53 -05005436 NotificationListenerService.REASON_ERROR, r.getStats());
Chris Wren6676dab2016-12-21 18:26:27 -05005437 mHandler.post(new Runnable() {
5438 @Override
5439 public void run() {
5440 mGroupHelper.onNotificationRemoved(n);
5441 }
5442 });
5443 }
5444 // ATTENTION: in a future release we will bail out here
5445 // so that we do not play sounds, show lights, etc. for invalid
5446 // notifications
5447 Slog.e(TAG, "WARNING: In a future release this will crash the app: "
5448 + n.getPackageName());
Chris Wren47633422016-01-22 09:56:59 -05005449 }
Chris Wren47633422016-01-22 09:56:59 -05005450
Julia Reynolds1fac86e2018-03-07 08:30:37 -05005451 maybeRecordInterruptionLocked(r);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05005452 } finally {
Julia Reynolds4b82f6d2017-01-04 10:47:41 -05005453 int N = mEnqueuedNotifications.size();
5454 for (int i = 0; i < N; i++) {
5455 final NotificationRecord enqueued = mEnqueuedNotifications.get(i);
5456 if (Objects.equals(key, enqueued.getKey())) {
5457 mEnqueuedNotifications.remove(i);
5458 break;
5459 }
5460 }
Chris Wren6676dab2016-12-21 18:26:27 -05005461 }
Chris Wren47633422016-01-22 09:56:59 -05005462 }
5463 }
5464 }
5465
Christoph Studer265c1052014-07-23 17:14:33 +02005466 /**
Julia Reynolds7217dc92018-03-07 12:12:09 -05005467 * If the notification differs enough visually, consider it a new interruptive notification.
5468 */
5469 @GuardedBy("mNotificationLock")
5470 @VisibleForTesting
5471 protected boolean isVisuallyInterruptive(NotificationRecord old, NotificationRecord r) {
Julia Reynolds760fa762018-06-19 15:39:23 -04005472 // Ignore summary updates because we don't display most of the information.
5473 if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
5474 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005475 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynolds760fa762018-06-19 15:39:23 -04005476 + r.getKey() + " is not interruptive: summary");
5477 }
5478 return false;
5479 }
5480
Dan Sandler7d67bd42018-05-15 14:06:38 -04005481 if (old == null) {
5482 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005483 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005484 + r.getKey() + " is interruptive: new notification");
5485 }
5486 return true;
5487 }
5488
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005489 if (r == null) {
5490 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005491 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005492 + r.getKey() + " is not interruptive: null");
5493 }
5494 return false;
5495 }
5496
Julia Reynolds7217dc92018-03-07 12:12:09 -05005497 Notification oldN = old.sbn.getNotification();
5498 Notification newN = r.sbn.getNotification();
Dan Sandler7d67bd42018-05-15 14:06:38 -04005499
Julia Reynolds7217dc92018-03-07 12:12:09 -05005500 if (oldN.extras == null || newN.extras == null) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005501 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005502 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005503 + r.getKey() + " is not interruptive: no extras");
5504 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005505 return false;
5506 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04005507
5508 // Ignore visual interruptions from foreground services because users
5509 // consider them one 'session'. Count them for everything else.
Julia Reynoldsa4fb9da2018-06-04 12:27:58 -04005510 if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005511 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005512 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005513 + r.getKey() + " is not interruptive: foreground service");
5514 }
Julia Reynoldse5c60452018-04-30 14:41:36 -04005515 return false;
5516 }
5517
Dan Sandler7d67bd42018-05-15 14:06:38 -04005518 final String oldTitle = String.valueOf(oldN.extras.get(Notification.EXTRA_TITLE));
5519 final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
5520 if (!Objects.equals(oldTitle, newTitle)) {
5521 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005522 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005523 + r.getKey() + " is interruptive: changed title");
Tony Mak180a9c42019-03-08 13:33:08 +00005524 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005525 oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
Tony Mak180a9c42019-03-08 13:33:08 +00005526 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005527 newTitle, newTitle.getClass(), newTitle.hashCode()));
5528 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005529 return true;
5530 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005531 // Do not compare Spannables (will always return false); compare unstyled Strings
5532 final String oldText = String.valueOf(oldN.extras.get(Notification.EXTRA_TEXT));
5533 final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
5534 if (!Objects.equals(oldText, newText)) {
5535 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005536 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005537 + r.getKey() + " is interruptive: changed text");
Tony Mak180a9c42019-03-08 13:33:08 +00005538 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005539 oldText, oldText.getClass(), oldText.hashCode()));
Tony Mak180a9c42019-03-08 13:33:08 +00005540 Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
Dan Sandler7d67bd42018-05-15 14:06:38 -04005541 newText, newText.getClass(), newText.hashCode()));
5542 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005543 return true;
5544 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005545 if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
5546 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005547 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005548 + r.getKey() + " is interruptive: completed progress");
5549 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005550 return true;
5551 }
5552 // Actions
5553 if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005554 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005555 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005556 + r.getKey() + " is interruptive: changed actions");
5557 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005558 return true;
5559 }
5560
5561 try {
5562 Notification.Builder oldB = Notification.Builder.recoverBuilder(getContext(), oldN);
5563 Notification.Builder newB = Notification.Builder.recoverBuilder(getContext(), newN);
5564
5565 // Style based comparisons
5566 if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005567 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005568 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005569 + r.getKey() + " is interruptive: styles differ");
5570 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005571 return true;
5572 }
5573
5574 // Remote views
5575 if (Notification.areRemoteViewsChanged(oldB, newB)) {
Dan Sandler7d67bd42018-05-15 14:06:38 -04005576 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005577 Slog.v(TAG, "INTERRUPTIVENESS: "
Dan Sandler7d67bd42018-05-15 14:06:38 -04005578 + r.getKey() + " is interruptive: remoteviews differ");
5579 }
Julia Reynolds7217dc92018-03-07 12:12:09 -05005580 return true;
5581 }
5582 } catch (Exception e) {
5583 Slog.w(TAG, "error recovering builder", e);
5584 }
Dan Sandler7d67bd42018-05-15 14:06:38 -04005585
Julia Reynolds7217dc92018-03-07 12:12:09 -05005586 return false;
5587 }
5588
5589 /**
Brad Stenningd2e7a972018-10-01 09:08:42 -07005590 * Check if the notification is classified as critical.
5591 *
5592 * @param record the record to test for criticality
5593 * @return {@code true} if notification is considered critical
5594 *
5595 * @see CriticalNotificationExtractor for criteria
5596 */
5597 private boolean isCritical(NotificationRecord record) {
5598 // 0 is the most critical
5599 return record.getCriticality() < CriticalNotificationExtractor.NORMAL;
5600 }
5601
5602 /**
Christoph Studer265c1052014-07-23 17:14:33 +02005603 * Ensures that grouped notification receive their special treatment.
5604 *
5605 * <p>Cancels group children if the new notification causes a group to lose
5606 * its summary.</p>
5607 *
5608 * <p>Updates mSummaryByGroupKey.</p>
5609 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04005610 @GuardedBy("mNotificationLock")
Christoph Studer265c1052014-07-23 17:14:33 +02005611 private void handleGroupedNotificationLocked(NotificationRecord r, NotificationRecord old,
5612 int callingUid, int callingPid) {
5613 StatusBarNotification sbn = r.sbn;
5614 Notification n = sbn.getNotification();
Selim Cinek5b03ce92016-05-18 15:16:58 -07005615 if (n.isGroupSummary() && !sbn.isAppGroup()) {
5616 // notifications without a group shouldn't be a summary, otherwise autobundling can
5617 // lead to bugs
5618 n.flags &= ~Notification.FLAG_GROUP_SUMMARY;
5619 }
5620
Christoph Studer265c1052014-07-23 17:14:33 +02005621 String group = sbn.getGroupKey();
5622 boolean isSummary = n.isGroupSummary();
5623
5624 Notification oldN = old != null ? old.sbn.getNotification() : null;
5625 String oldGroup = old != null ? old.sbn.getGroupKey() : null;
5626 boolean oldIsSummary = old != null && oldN.isGroupSummary();
5627
5628 if (oldIsSummary) {
5629 NotificationRecord removedSummary = mSummaryByGroupKey.remove(oldGroup);
5630 if (removedSummary != old) {
5631 String removedKey =
5632 removedSummary != null ? removedSummary.getKey() : "<null>";
5633 Slog.w(TAG, "Removed summary didn't match old notification: old=" + old.getKey() +
5634 ", removed=" + removedKey);
5635 }
5636 }
5637 if (isSummary) {
5638 mSummaryByGroupKey.put(group, r);
5639 }
5640
5641 // Clear out group children of the old notification if the update
5642 // causes the group summary to go away. This happens when the old
5643 // notification was a summary and the new one isn't, or when the old
5644 // notification was a summary and its group key changed.
5645 if (oldIsSummary && (!isSummary || !oldGroup.equals(group))) {
Beverly40239d92017-07-07 10:20:41 -04005646 cancelGroupChildrenLocked(old, callingUid, callingPid, null, false /* sendDelete */,
5647 null);
Christoph Studer265c1052014-07-23 17:14:33 +02005648 }
5649 }
5650
Chris Wren93bb8b82016-03-29 14:35:05 -04005651 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005652 @GuardedBy("mNotificationLock")
Julia Reynolds2a128742016-11-28 14:29:25 -05005653 void scheduleTimeoutLocked(NotificationRecord record) {
Julia Reynoldsbad42972017-04-25 13:52:49 -04005654 if (record.getNotification().getTimeoutAfter() > 0) {
Julia Reynolds2a128742016-11-28 14:29:25 -05005655 final PendingIntent pi = PendingIntent.getBroadcast(getContext(),
5656 REQUEST_CODE_TIMEOUT,
5657 new Intent(ACTION_NOTIFICATION_TIMEOUT)
5658 .setData(new Uri.Builder().scheme(SCHEME_TIMEOUT)
5659 .appendPath(record.getKey()).build())
5660 .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
5661 .putExtra(EXTRA_KEY, record.getKey()),
5662 PendingIntent.FLAG_UPDATE_CURRENT);
Julia Reynolds50989772017-02-23 14:32:16 -05005663 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
Julia Reynoldsbad42972017-04-25 13:52:49 -04005664 SystemClock.elapsedRealtime() + record.getNotification().getTimeoutAfter(), pi);
Julia Reynolds2a128742016-11-28 14:29:25 -05005665 }
5666 }
5667
5668 @VisibleForTesting
Julia Reynolds88860ce2017-06-01 16:55:49 -04005669 @GuardedBy("mNotificationLock")
Chris Wren93bb8b82016-03-29 14:35:05 -04005670 void buzzBeepBlinkLocked(NotificationRecord record) {
Qiao (Adora) Zhang47b553c2019-04-15 20:42:57 +00005671 if (mIsAutomotive && !mNotificationEffectsEnabledForAutomotive) {
5672 return;
5673 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005674 boolean buzz = false;
5675 boolean beep = false;
5676 boolean blink = false;
5677
Chris Wrena3446562014-06-03 18:11:47 -04005678 final Notification notification = record.sbn.getNotification();
Chris Wren93bb8b82016-03-29 14:35:05 -04005679 final String key = record.getKey();
Chris Wrena3446562014-06-03 18:11:47 -04005680
5681 // Should this notification make noise, vibe, or use the LED?
Julia Reynolds85769912016-10-25 09:08:57 -04005682 final boolean aboveThreshold =
Adora Zhang963328f2018-11-15 18:17:19 -08005683 mIsAutomotive
5684 ? record.getImportance() > NotificationManager.IMPORTANCE_DEFAULT
5685 : record.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT;
Chris Wren93bb8b82016-03-29 14:35:05 -04005686
5687 // Remember if this notification already owns the notification channels.
5688 boolean wasBeep = key != null && key.equals(mSoundNotificationKey);
5689 boolean wasBuzz = key != null && key.equals(mVibrateNotificationKey);
Chris Wren93bb8b82016-03-29 14:35:05 -04005690 // These are set inside the conditional if the notification is allowed to make noise.
5691 boolean hasValidVibrate = false;
5692 boolean hasValidSound = false;
Julia Reynolds94187562017-10-10 13:58:49 -04005693 boolean sentAccessibilityEvent = false;
5694 // If the notification will appear in the status bar, it should send an accessibility
5695 // event
5696 if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
5697 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5698 sentAccessibilityEvent = true;
5699 }
Chris Wrena3446562014-06-03 18:11:47 -04005700
Julia Reynolds76c096d2017-06-19 08:16:04 -04005701 if (aboveThreshold && isNotificationForCurrentUser(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005702
Julia Reynolds76c096d2017-06-19 08:16:04 -04005703 if (mSystemReady && mAudioManager != null) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005704 Uri soundUri = record.getSound();
5705 hasValidSound = soundUri != null && !Uri.EMPTY.equals(soundUri);
5706 long[] vibration = record.getVibration();
5707 // Demote sound to vibration if vibration missing & phone in vibration mode.
5708 if (vibration == null
5709 && hasValidSound
5710 && (mAudioManager.getRingerModeInternal()
Julia Reynolds85896572017-09-20 12:54:52 -04005711 == AudioManager.RINGER_MODE_VIBRATE)
5712 && mAudioManager.getStreamVolume(
5713 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) == 0) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005714 vibration = mFallbackVibrationPattern;
Chris Wren93bb8b82016-03-29 14:35:05 -04005715 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005716 hasValidVibrate = vibration != null;
Marta Białka39c992f2011-03-10 10:27:24 +01005717
Julia Reynolds76c096d2017-06-19 08:16:04 -04005718 boolean hasAudibleAlert = hasValidSound || hasValidVibrate;
Julia Reynolds76c096d2017-06-19 08:16:04 -04005719 if (hasAudibleAlert && !shouldMuteNotificationLocked(record)) {
Julia Reynolds94187562017-10-10 13:58:49 -04005720 if (!sentAccessibilityEvent) {
5721 sendAccessibilityEvent(notification, record.sbn.getPackageName());
5722 sentAccessibilityEvent = true;
5723 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005724 if (DBG) Slog.v(TAG, "Interrupting!");
Julia Reynolds7c96b582017-05-25 12:35:36 -04005725 if (hasValidSound) {
Eric Laurent7412abc2019-07-12 18:26:29 -07005726 if (isInCall()) {
Julia Reynolds7c96b582017-05-25 12:35:36 -04005727 playInCallNotification();
5728 beep = true;
5729 } else {
5730 beep = playSound(record, soundUri);
5731 }
Seungho Lee55102a82018-12-09 19:27:36 +09005732 if(beep) {
5733 mSoundNotificationKey = key;
5734 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005735 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005736
Julia Reynolds7c96b582017-05-25 12:35:36 -04005737 final boolean ringerModeSilent =
5738 mAudioManager.getRingerModeInternal()
5739 == AudioManager.RINGER_MODE_SILENT;
Eric Laurent7412abc2019-07-12 18:26:29 -07005740 if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005741 buzz = playVibration(record, vibration, hasValidSound);
Seungho Lee55102a82018-12-09 19:27:36 +09005742 if(buzz) {
5743 mVibrateNotificationKey = key;
5744 }
Julia Reynolds7c96b582017-05-25 12:35:36 -04005745 }
Tyler Gunn48f86272018-07-03 12:38:49 -07005746 } else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
5747 hasValidSound = false;
Chris Wrena3446562014-06-03 18:11:47 -04005748 }
5749 }
Chris Wren93bb8b82016-03-29 14:35:05 -04005750 }
5751 // If a notification is updated to remove the actively playing sound or vibrate,
5752 // cancel that feedback now
5753 if (wasBeep && !hasValidSound) {
5754 clearSoundLocked();
5755 }
5756 if (wasBuzz && !hasValidVibrate) {
5757 clearVibrateLocked();
Chris Wrena3446562014-06-03 18:11:47 -04005758 }
5759
5760 // light
5761 // release the light
Chris Wren93bb8b82016-03-29 14:35:05 -04005762 boolean wasShowLights = mLights.remove(key);
Julia Reynolds28149f62018-07-03 10:43:35 -04005763 if (canShowLightsLocked(record, aboveThreshold)) {
Chris Wren93bb8b82016-03-29 14:35:05 -04005764 mLights.add(key);
Chris Wrena3446562014-06-03 18:11:47 -04005765 updateLightsLocked();
Chris Wren5116a822014-06-04 15:59:50 -04005766 if (mUseAttentionLight) {
5767 mAttentionLight.pulse();
5768 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005769 blink = true;
Chris Wrena3446562014-06-03 18:11:47 -04005770 } else if (wasShowLights) {
5771 updateLightsLocked();
5772 }
Chris Wren82ba59d2015-06-05 11:23:44 -04005773 if (buzz || beep || blink) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005774 // Ignore summary updates because we don't display most of the information.
5775 if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
5776 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005777 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynolds28149f62018-07-03 10:43:35 -04005778 + record.getKey() + " is not interruptive: summary");
5779 }
5780 } else {
5781 if (DEBUG_INTERRUPTIVENESS) {
Tony Mak180a9c42019-03-08 13:33:08 +00005782 Slog.v(TAG, "INTERRUPTIVENESS: "
Julia Reynolds28149f62018-07-03 10:43:35 -04005783 + record.getKey() + " is interruptive: alerted");
5784 }
5785 record.setInterruptive(true);
5786 }
Julia Reynolds445cfa82017-05-08 15:41:45 -04005787 MetricsLogger.action(record.getLogMaker()
5788 .setCategory(MetricsEvent.NOTIFICATION_ALERT)
5789 .setType(MetricsEvent.TYPE_OPEN)
5790 .setSubtype((buzz ? 1 : 0) | (beep ? 2 : 0) | (blink ? 4 : 0)));
5791 EventLogTags.writeNotificationAlert(key, buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
John Spurlockcad57682014-07-26 17:09:56 -04005792 }
Gus Prevasa3226492018-10-23 11:10:09 -04005793 record.setAudiblyAlerted(buzz || beep);
Chris Wrena3446562014-06-03 18:11:47 -04005794 }
5795
Julia Reynolds88860ce2017-06-01 16:55:49 -04005796 @GuardedBy("mNotificationLock")
Julia Reynolds28149f62018-07-03 10:43:35 -04005797 boolean canShowLightsLocked(final NotificationRecord record, boolean aboveThreshold) {
5798 // device lacks light
5799 if (!mHasLight) {
5800 return false;
5801 }
5802 // user turned lights off globally
5803 if (!mNotificationPulseEnabled) {
5804 return false;
5805 }
5806 // the notification/channel has no light
5807 if (record.getLight() == null) {
5808 return false;
5809 }
5810 // unimportant notification
5811 if (!aboveThreshold) {
5812 return false;
5813 }
5814 // suppressed due to DND
5815 if ((record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_LIGHTS) != 0) {
5816 return false;
5817 }
5818 // Suppressed because it's a silent update
5819 final Notification notification = record.getNotification();
Mady Mellor66efd5e2019-05-15 13:38:11 -07005820 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005821 return false;
5822 }
5823 // Suppressed because another notification in its group handles alerting
5824 if (record.sbn.isGroup() && record.getNotification().suppressAlertingDueToGrouping()) {
5825 return false;
5826 }
5827 // not if in call or the screen's on
Eric Laurent7412abc2019-07-12 18:26:29 -07005828 if (isInCall() || mScreenOn) {
Julia Reynolds28149f62018-07-03 10:43:35 -04005829 return false;
5830 }
5831
5832 return true;
5833 }
5834
5835 @GuardedBy("mNotificationLock")
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005836 boolean shouldMuteNotificationLocked(final NotificationRecord record) {
Julia Reynolds76c096d2017-06-19 08:16:04 -04005837 // Suppressed because it's a silent update
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005838 final Notification notification = record.getNotification();
Mady Mellor66efd5e2019-05-15 13:38:11 -07005839 if (record.isUpdate && (notification.flags & FLAG_ONLY_ALERT_ONCE) != 0) {
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005840 return true;
5841 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005842
Julia Reynolds76c096d2017-06-19 08:16:04 -04005843 // muted by listener
5844 final String disableEffects = disableNotificationEffects(record);
5845 if (disableEffects != null) {
5846 ZenLog.traceDisableEffects(record, disableEffects);
5847 return true;
5848 }
5849
5850 // suppressed due to DND
5851 if (record.isIntercepted()) {
5852 return true;
5853 }
5854
5855 // Suppressed because another notification in its group handles alerting
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005856 if (record.sbn.isGroup()) {
Julia Reynolds79dfdd62018-04-17 15:36:33 -04005857 if (notification.suppressAlertingDueToGrouping()) {
5858 return true;
5859 }
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005860 }
Julia Reynolds76c096d2017-06-19 08:16:04 -04005861
Julia Reynolds65b85cf2017-07-20 09:19:20 -04005862 // Suppressed for being too recently noisy
5863 final String pkg = record.sbn.getPackageName();
5864 if (mUsageStats.isAlertRateLimited(pkg)) {
5865 Slog.e(TAG, "Muting recently noisy " + record.getKey());
5866 return true;
5867 }
5868
Julia Reynoldsa79c3712017-04-21 10:29:57 -04005869 return false;
5870 }
5871
Julia Reynolds0c299d42016-11-15 14:37:04 -05005872 private boolean playSound(final NotificationRecord record, Uri soundUri) {
5873 boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
Jean-Michel Triviec2bb182018-03-23 18:04:00 -07005874 // play notifications if there is no user of exclusive audio focus
5875 // and the stream volume is not 0 (non-zero volume implies not silenced by SILENT or
5876 // VIBRATE ringer mode)
5877 if (!mAudioManager.isAudioFocusExclusive()
5878 && (mAudioManager.getStreamVolume(
5879 AudioAttributes.toLegacyStreamType(record.getAudioAttributes())) != 0)) {
Julia Reynolds0c299d42016-11-15 14:37:04 -05005880 final long identity = Binder.clearCallingIdentity();
5881 try {
5882 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5883 if (player != null) {
5884 if (DBG) Slog.v(TAG, "Playing sound " + soundUri
5885 + " with attributes " + record.getAudioAttributes());
5886 player.playAsync(soundUri, record.sbn.getUser(), looping,
5887 record.getAudioAttributes());
5888 return true;
5889 }
5890 } catch (RemoteException e) {
5891 } finally {
5892 Binder.restoreCallingIdentity(identity);
5893 }
5894 }
5895 return false;
5896 }
5897
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005898 private boolean playVibration(final NotificationRecord record, long[] vibration,
5899 boolean delayVibForSound) {
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005900 // Escalate privileges so we can use the vibrator even if the
5901 // notifying app does not have the VIBRATE permission.
5902 long identity = Binder.clearCallingIdentity();
5903 try {
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005904 final VibrationEffect effect;
5905 try {
5906 final boolean insistent =
5907 (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
5908 effect = VibrationEffect.createWaveform(
5909 vibration, insistent ? 0 : -1 /*repeatIndex*/);
5910 } catch (IllegalArgumentException e) {
5911 Slog.e(TAG, "Error creating vibration waveform with pattern: " +
5912 Arrays.toString(vibration));
5913 return false;
5914 }
5915 if (delayVibForSound) {
5916 new Thread(() -> {
5917 // delay the vibration by the same amount as the notification sound
5918 final int waitMs = mAudioManager.getFocusRampTimeMs(
5919 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
5920 record.getAudioAttributes());
5921 if (DBG) Slog.v(TAG, "Delaying vibration by " + waitMs + "ms");
5922 try {
5923 Thread.sleep(waitMs);
5924 } catch (InterruptedException e) { }
Seungho Leede933882018-10-31 21:49:09 +09005925
5926 // Notifications might be canceled before it actually vibrates due to waitMs,
5927 // so need to check the notification still valide for vibrate.
5928 synchronized (mNotificationLock) {
5929 if (mNotificationsByKey.get(record.getKey()) != null) {
5930 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getOpPkg(),
5931 effect, "Notification (delayed)", record.getAudioAttributes());
5932 } else {
5933 Slog.e(TAG, "No vibration for canceled notification : " + record.getKey());
5934 }
5935 }
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005936 }).start();
5937 } else {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04005938 mVibrator.vibrate(record.sbn.getUid(), record.sbn.getPackageName(),
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01005939 effect, "Notification", record.getAudioAttributes());
Jean-Michel Triviea0eb5f2017-05-25 18:32:40 -07005940 }
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04005941 return true;
5942 } finally{
5943 Binder.restoreCallingIdentity(identity);
5944 }
5945 }
5946
Julia Reynolds7c96b582017-05-25 12:35:36 -04005947 private boolean isNotificationForCurrentUser(NotificationRecord record) {
5948 final int currentUser;
5949 final long token = Binder.clearCallingIdentity();
5950 try {
5951 currentUser = ActivityManager.getCurrentUser();
5952 } finally {
5953 Binder.restoreCallingIdentity(token);
5954 }
5955 return (record.getUserId() == UserHandle.USER_ALL ||
5956 record.getUserId() == currentUser ||
5957 mUserProfiles.isCurrentProfile(record.getUserId()));
5958 }
5959
Beverly5d463b62017-07-26 14:13:40 -04005960 protected void playInCallNotification() {
Beverly28c3d162018-06-28 11:37:53 -04005961 if (mAudioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_NORMAL
5962 && Settings.Secure.getInt(getContext().getContentResolver(),
5963 Settings.Secure.IN_CALL_NOTIFICATION_ENABLED, 1) != 0) {
5964 new Thread() {
5965 @Override
5966 public void run() {
5967 final long identity = Binder.clearCallingIdentity();
5968 try {
5969 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
5970 if (player != null) {
5971 if (mCallNotificationToken != null) {
5972 player.stop(mCallNotificationToken);
5973 }
5974 mCallNotificationToken = new Binder();
5975 player.play(mCallNotificationToken, mInCallNotificationUri,
5976 mInCallNotificationAudioAttributes,
5977 mInCallNotificationVolume, false);
luochaojiang50e5273c2018-04-16 16:55:03 +08005978 }
Beverly28c3d162018-06-28 11:37:53 -04005979 } catch (RemoteException e) {
5980 } finally {
5981 Binder.restoreCallingIdentity(identity);
Marta Białka39c992f2011-03-10 10:27:24 +01005982 }
Marta Białka39c992f2011-03-10 10:27:24 +01005983 }
Beverly28c3d162018-06-28 11:37:53 -04005984 }.start();
5985 }
Marta Białka39c992f2011-03-10 10:27:24 +01005986 }
5987
Julia Reynolds88860ce2017-06-01 16:55:49 -04005988 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08005989 void showNextToastLocked() {
5990 ToastRecord record = mToastQueue.get(0);
5991 while (record != null) {
5992 if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
5993 try {
Svetoslav Ganovaa076532016-08-01 19:16:43 -07005994 record.callback.show(record.token);
Robert Carr997427342018-02-28 18:06:10 -08005995 scheduleDurationReachedLocked(record);
Adam Lesinski182f73f2013-12-05 16:48:06 -08005996 return;
5997 } catch (RemoteException e) {
5998 Slog.w(TAG, "Object died trying to show notification " + record.callback
5999 + " in package " + record.pkg);
6000 // remove it from the list and let the process die
6001 int index = mToastQueue.indexOf(record);
6002 if (index >= 0) {
6003 mToastQueue.remove(index);
6004 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07006005 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006006 if (mToastQueue.size() > 0) {
6007 record = mToastQueue.get(0);
6008 } else {
6009 record = null;
6010 }
6011 }
6012 }
6013 }
6014
Julia Reynolds88860ce2017-06-01 16:55:49 -04006015 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006016 void cancelToastLocked(int index) {
6017 ToastRecord record = mToastQueue.get(index);
6018 try {
6019 record.callback.hide();
6020 } catch (RemoteException e) {
6021 Slog.w(TAG, "Object died trying to hide notification " + record.callback
6022 + " in package " + record.pkg);
6023 // don't worry about this, we're about to remove it from
6024 // the list anyway
6025 }
Svetoslav Ganovaa076532016-08-01 19:16:43 -07006026
6027 ToastRecord lastToast = mToastQueue.remove(index);
Robert Carr997427342018-02-28 18:06:10 -08006028
6029 mWindowManagerInternal.removeWindowToken(lastToast.token, false /* removeWindows */,
Jeff Chang48ecef42018-08-09 16:31:59 +08006030 lastToast.displayId);
Robert Carr997427342018-02-28 18:06:10 -08006031 // We passed 'false' for 'removeWindows' so that the client has time to stop
6032 // rendering (as hide above is a one-way message), otherwise we could crash
6033 // a client which was actively using a surface made from the token. However
6034 // we need to schedule a timeout to make sure the token is eventually killed
6035 // one way or another.
Jeff Chang48ecef42018-08-09 16:31:59 +08006036 scheduleKillTokenTimeout(lastToast);
Svetoslav Ganovaa076532016-08-01 19:16:43 -07006037
6038 keepProcessAliveIfNeededLocked(record.pid);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006039 if (mToastQueue.size() > 0) {
6040 // Show the next one. If the callback fails, this will remove
6041 // it from the list, so don't assume that the list hasn't changed
6042 // after this point.
6043 showNextToastLocked();
6044 }
6045 }
6046
Jeff Chang48ecef42018-08-09 16:31:59 +08006047 void finishTokenLocked(IBinder t, int displayId) {
Robert Carr997427342018-02-28 18:06:10 -08006048 mHandler.removeCallbacksAndMessages(t);
6049 // We pass 'true' for 'removeWindows' to let the WindowManager destroy any
6050 // remaining surfaces as either the client has called finishToken indicating
6051 // it has successfully removed the views, or the client has timed out
6052 // at which point anything goes.
Jeff Chang48ecef42018-08-09 16:31:59 +08006053 mWindowManagerInternal.removeWindowToken(t, true /* removeWindows */, displayId);
Robert Carr997427342018-02-28 18:06:10 -08006054 }
6055
Julia Reynolds88860ce2017-06-01 16:55:49 -04006056 @GuardedBy("mToastQueue")
Robert Carr997427342018-02-28 18:06:10 -08006057 private void scheduleDurationReachedLocked(ToastRecord r)
Adam Lesinski182f73f2013-12-05 16:48:06 -08006058 {
6059 mHandler.removeCallbacksAndMessages(r);
Robert Carr997427342018-02-28 18:06:10 -08006060 Message m = Message.obtain(mHandler, MESSAGE_DURATION_REACHED, r);
Rhed Jao406d3a22018-11-30 19:28:58 +08006061 int delay = r.duration == Toast.LENGTH_LONG ? LONG_DELAY : SHORT_DELAY;
6062 // Accessibility users may need longer timeout duration. This api compares original delay
6063 // with user's preference and return longer one. It returns original delay if there's no
6064 // preference.
6065 delay = mAccessibilityManager.getRecommendedTimeoutMillis(delay,
6066 AccessibilityManager.FLAG_CONTENT_TEXT);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006067 mHandler.sendMessageDelayed(m, delay);
6068 }
6069
Robert Carr997427342018-02-28 18:06:10 -08006070 private void handleDurationReached(ToastRecord record)
Adam Lesinski182f73f2013-12-05 16:48:06 -08006071 {
6072 if (DBG) Slog.d(TAG, "Timeout pkg=" + record.pkg + " callback=" + record.callback);
6073 synchronized (mToastQueue) {
6074 int index = indexOfToastLocked(record.pkg, record.callback);
6075 if (index >= 0) {
6076 cancelToastLocked(index);
6077 }
6078 }
6079 }
6080
Julia Reynolds88860ce2017-06-01 16:55:49 -04006081 @GuardedBy("mToastQueue")
Jeff Chang48ecef42018-08-09 16:31:59 +08006082 private void scheduleKillTokenTimeout(ToastRecord r)
Robert Carr997427342018-02-28 18:06:10 -08006083 {
Jeff Chang48ecef42018-08-09 16:31:59 +08006084 mHandler.removeCallbacksAndMessages(r);
6085 Message m = Message.obtain(mHandler, MESSAGE_FINISH_TOKEN_TIMEOUT, r);
Robert Carr3406d462018-03-15 16:19:07 -07006086 mHandler.sendMessageDelayed(m, FINISH_TOKEN_TIMEOUT);
Robert Carr997427342018-02-28 18:06:10 -08006087 }
6088
Jeff Chang48ecef42018-08-09 16:31:59 +08006089 private void handleKillTokenTimeout(ToastRecord record)
Robert Carr997427342018-02-28 18:06:10 -08006090 {
Jeff Chang48ecef42018-08-09 16:31:59 +08006091 if (DBG) Slog.d(TAG, "Kill Token Timeout token=" + record.token);
Robert Carr997427342018-02-28 18:06:10 -08006092 synchronized (mToastQueue) {
Jeff Chang48ecef42018-08-09 16:31:59 +08006093 finishTokenLocked(record.token, record.displayId);
Robert Carr997427342018-02-28 18:06:10 -08006094 }
6095 }
6096
6097 @GuardedBy("mToastQueue")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006098 int indexOfToastLocked(String pkg, ITransientNotification callback)
6099 {
6100 IBinder cbak = callback.asBinder();
6101 ArrayList<ToastRecord> list = mToastQueue;
6102 int len = list.size();
6103 for (int i=0; i<len; i++) {
6104 ToastRecord r = list.get(i);
Beverly Taia7ed0ab2018-06-11 14:50:36 +00006105 if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
Adam Lesinski182f73f2013-12-05 16:48:06 -08006106 return i;
6107 }
6108 }
6109 return -1;
6110 }
6111
Julia Reynolds88860ce2017-06-01 16:55:49 -04006112 @GuardedBy("mToastQueue")
Svetoslav Ganovaa076532016-08-01 19:16:43 -07006113 void keepProcessAliveIfNeededLocked(int pid)
Adam Lesinski182f73f2013-12-05 16:48:06 -08006114 {
6115 int toastCount = 0; // toasts from this pid
6116 ArrayList<ToastRecord> list = mToastQueue;
6117 int N = list.size();
6118 for (int i=0; i<N; i++) {
6119 ToastRecord r = list.get(i);
6120 if (r.pid == pid) {
6121 toastCount++;
6122 }
6123 }
6124 try {
Dianne Hackbornf965f402017-05-04 23:27:23 -07006125 mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
Adam Lesinski182f73f2013-12-05 16:48:06 -08006126 } catch (RemoteException e) {
6127 // Shouldn't happen.
6128 }
6129 }
6130
Chris Wrenf9536642014-04-17 10:01:54 -04006131 private void handleRankingReconsideration(Message message) {
Chris Wren470c1ac2014-05-21 15:28:10 -04006132 if (!(message.obj instanceof RankingReconsideration)) return;
6133 RankingReconsideration recon = (RankingReconsideration) message.obj;
6134 recon.run();
Chris Wren333a61c2014-05-28 16:40:57 -04006135 boolean changed;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006136 synchronized (mNotificationLock) {
Chris Wren470c1ac2014-05-21 15:28:10 -04006137 final NotificationRecord record = mNotificationsByKey.get(recon.getKey());
6138 if (record == null) {
6139 return;
Chris Wrenf9536642014-04-17 10:01:54 -04006140 }
Chris Wren333a61c2014-05-28 16:40:57 -04006141 int indexBefore = findNotificationRecordIndexLocked(record);
6142 boolean interceptBefore = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006143 int visibilityBefore = record.getPackageVisibilityOverride();
Chris Wren470c1ac2014-05-21 15:28:10 -04006144 recon.applyChangesLocked(record);
Chris Wren333a61c2014-05-28 16:40:57 -04006145 applyZenModeLocked(record);
Chris Wren54bbef42014-07-09 18:37:56 -04006146 mRankingHelper.sort(mNotificationList);
Chris Wren333a61c2014-05-28 16:40:57 -04006147 int indexAfter = findNotificationRecordIndexLocked(record);
6148 boolean interceptAfter = record.isIntercepted();
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006149 int visibilityAfter = record.getPackageVisibilityOverride();
6150 changed = indexBefore != indexAfter || interceptBefore != interceptAfter
6151 || visibilityBefore != visibilityAfter;
Julia Reynolds16eb52a2017-06-23 16:13:20 -04006152 if (interceptBefore && !interceptAfter
Julia Reynoldsd6730072019-01-04 12:52:52 -05006153 && record.isNewEnoughForAlerting(System.currentTimeMillis())) {
Chris Wrena3446562014-06-03 18:11:47 -04006154 buzzBeepBlinkLocked(record);
6155 }
Chris Wrenf9536642014-04-17 10:01:54 -04006156 }
Chris Wren333a61c2014-05-28 16:40:57 -04006157 if (changed) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006158 mHandler.scheduleSendRankingUpdate();
Chris Wren470c1ac2014-05-21 15:28:10 -04006159 }
6160 }
6161
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006162 void handleRankingSort() {
Chris Wren89aa2262017-05-05 18:05:56 -04006163 if (mRankingHelper == null) return;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006164 synchronized (mNotificationLock) {
Chris Wren54bbef42014-07-09 18:37:56 -04006165 final int N = mNotificationList.size();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006166 // Any field that can change via one of the extractors needs to be added here.
6167 ArrayList<String> orderBefore = new ArrayList<>(N);
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006168 int[] visibilities = new int[N];
Julia Reynolds924eed12017-01-19 09:52:07 -05006169 boolean[] showBadges = new boolean[N];
Julia Reynolds4509ce72019-01-31 13:12:43 -05006170 boolean[] allowBubbles = new boolean[N];
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006171 ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
6172 ArrayList<String> groupKeyBefore = new ArrayList<>(N);
6173 ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
6174 ArrayList<ArrayList<SnoozeCriterion>> snoozeCriteriaBefore = new ArrayList<>(N);
Julia Reynolds503ed942017-10-04 16:04:56 -04006175 ArrayList<Integer> userSentimentBefore = new ArrayList<>(N);
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05006176 ArrayList<Integer> suppressVisuallyBefore = new ArrayList<>(N);
Gustav Sennton1463d832018-11-06 16:12:48 +00006177 ArrayList<ArrayList<Notification.Action>> systemSmartActionsBefore = new ArrayList<>(N);
Tony Makc9acf672018-07-20 13:58:24 +02006178 ArrayList<ArrayList<CharSequence>> smartRepliesBefore = new ArrayList<>(N);
Julia Reynolds27c0a962018-12-10 12:37:28 -05006179 int[] importancesBefore = new int[N];
Chris Wren54bbef42014-07-09 18:37:56 -04006180 for (int i = 0; i < N; i++) {
6181 final NotificationRecord r = mNotificationList.get(i);
6182 orderBefore.add(r.getKey());
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006183 visibilities[i] = r.getPackageVisibilityOverride();
Julia Reynolds924eed12017-01-19 09:52:07 -05006184 showBadges[i] = r.canShowBadge();
Julia Reynolds4509ce72019-01-31 13:12:43 -05006185 allowBubbles[i] = r.canBubble();
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006186 channelBefore.add(r.getChannel());
6187 groupKeyBefore.add(r.getGroupKey());
6188 overridePeopleBefore.add(r.getPeopleOverride());
6189 snoozeCriteriaBefore.add(r.getSnoozeCriteria());
Julia Reynolds503ed942017-10-04 16:04:56 -04006190 userSentimentBefore.add(r.getUserSentiment());
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05006191 suppressVisuallyBefore.add(r.getSuppressedVisualEffects());
Gustav Sennton1463d832018-11-06 16:12:48 +00006192 systemSmartActionsBefore.add(r.getSystemGeneratedSmartActions());
Tony Makc9acf672018-07-20 13:58:24 +02006193 smartRepliesBefore.add(r.getSmartReplies());
Julia Reynolds27c0a962018-12-10 12:37:28 -05006194 importancesBefore[i] = r.getImportance();
Chris Wren54bbef42014-07-09 18:37:56 -04006195 mRankingHelper.extractSignals(r);
6196 }
Chris Wren19a02b02015-12-22 10:34:22 -05006197 mRankingHelper.sort(mNotificationList);
Chris Wren54bbef42014-07-09 18:37:56 -04006198 for (int i = 0; i < N; i++) {
Chris Wren3ad4e3a2014-09-02 17:23:51 -04006199 final NotificationRecord r = mNotificationList.get(i);
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006200 if (!orderBefore.get(i).equals(r.getKey())
Julia Reynolds69766692016-02-01 15:35:08 -05006201 || visibilities[i] != r.getPackageVisibilityOverride()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006202 || showBadges[i] != r.canShowBadge()
Julia Reynolds4509ce72019-01-31 13:12:43 -05006203 || allowBubbles[i] != r.canBubble()
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006204 || !Objects.equals(channelBefore.get(i), r.getChannel())
6205 || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
6206 || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
Julia Reynolds503ed942017-10-04 16:04:56 -04006207 || !Objects.equals(snoozeCriteriaBefore.get(i), r.getSnoozeCriteria())
Julia Reynoldsc861a3d2018-02-15 10:34:49 -05006208 || !Objects.equals(userSentimentBefore.get(i), r.getUserSentiment())
6209 || !Objects.equals(suppressVisuallyBefore.get(i),
Tony Mak628cb932018-06-19 18:30:41 +01006210 r.getSuppressedVisualEffects())
Gustav Sennton1463d832018-11-06 16:12:48 +00006211 || !Objects.equals(systemSmartActionsBefore.get(i),
6212 r.getSystemGeneratedSmartActions())
Julia Reynolds27c0a962018-12-10 12:37:28 -05006213 || !Objects.equals(smartRepliesBefore.get(i), r.getSmartReplies())
6214 || importancesBefore[i] != r.getImportance()) {
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006215 mHandler.scheduleSendRankingUpdate();
Chris Wren54bbef42014-07-09 18:37:56 -04006216 return;
6217 }
6218 }
6219 }
6220 }
6221
Julia Reynolds88860ce2017-06-01 16:55:49 -04006222 @GuardedBy("mNotificationLock")
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04006223 private void recordCallerLocked(NotificationRecord record) {
6224 if (mZenModeHelper.isCall(record)) {
6225 mZenModeHelper.recordCaller(record);
6226 }
6227 }
6228
Christoph Studerd5092bc2014-07-03 17:47:58 +02006229 // let zen mode evaluate this record
Julia Reynolds88860ce2017-06-01 16:55:49 -04006230 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04006231 private void applyZenModeLocked(NotificationRecord record) {
Christoph Studerd5092bc2014-07-03 17:47:58 +02006232 record.setIntercepted(mZenModeHelper.shouldIntercept(record));
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006233 if (record.isIntercepted()) {
Julia Reynoldsccc6ae62018-03-01 16:24:49 -05006234 record.setSuppressedVisualEffects(
Beverlyff2df9b2018-10-10 16:54:10 -04006235 mZenModeHelper.getConsolidatedNotificationPolicy().suppressedVisualEffects);
Julia Reynolds445cfa82017-05-08 15:41:45 -04006236 } else {
6237 record.setSuppressedVisualEffects(0);
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05006238 }
Chris Wren333a61c2014-05-28 16:40:57 -04006239 }
6240
Julia Reynolds88860ce2017-06-01 16:55:49 -04006241 @GuardedBy("mNotificationLock")
Chris Wren470c1ac2014-05-21 15:28:10 -04006242 private int findNotificationRecordIndexLocked(NotificationRecord target) {
Chris Wren54bbef42014-07-09 18:37:56 -04006243 return mRankingHelper.indexOf(mNotificationList, target);
Chris Wrenf9536642014-04-17 10:01:54 -04006244 }
6245
Chris Wrenf9536642014-04-17 10:01:54 -04006246 private void handleSendRankingUpdate() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006247 synchronized (mNotificationLock) {
Beverly5a20a5e2018-03-06 15:02:44 -05006248 mListeners.notifyRankingUpdateLocked(null);
Chris Wrenf9536642014-04-17 10:01:54 -04006249 }
6250 }
6251
John Spurlockd8afe3c2014-08-01 14:04:07 -04006252 private void scheduleListenerHintsChanged(int state) {
6253 mHandler.removeMessages(MESSAGE_LISTENER_HINTS_CHANGED);
6254 mHandler.obtainMessage(MESSAGE_LISTENER_HINTS_CHANGED, state, 0).sendToTarget();
John Spurlock1fa865f2014-07-21 14:56:39 -04006255 }
6256
Christoph Studer85a384b2014-08-27 20:16:15 +02006257 private void scheduleInterruptionFilterChanged(int listenerInterruptionFilter) {
6258 mHandler.removeMessages(MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED);
6259 mHandler.obtainMessage(
6260 MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED,
6261 listenerInterruptionFilter,
6262 0).sendToTarget();
6263 }
6264
John Spurlockd8afe3c2014-08-01 14:04:07 -04006265 private void handleListenerHintsChanged(int hints) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006266 synchronized (mNotificationLock) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04006267 mListeners.notifyListenerHintsChangedLocked(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04006268 }
6269 }
6270
Christoph Studer85a384b2014-08-27 20:16:15 +02006271 private void handleListenerInterruptionFilterChanged(int interruptionFilter) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006272 synchronized (mNotificationLock) {
Christoph Studer85a384b2014-08-27 20:16:15 +02006273 mListeners.notifyInterruptionFilterChanged(interruptionFilter);
6274 }
6275 }
6276
Julia Reynoldsb0405592018-11-26 17:01:13 -05006277 private void handleOnPackageChanged(boolean removingPackage, int changeUserId,
6278 String[] pkgList, int[] uidList) {
Julia Reynolds996c7c12019-05-24 10:25:33 -04006279 boolean preferencesChanged = removingPackage;
Julia Reynoldsb0405592018-11-26 17:01:13 -05006280 mListeners.onPackagesChanged(removingPackage, pkgList, uidList);
6281 mAssistants.onPackagesChanged(removingPackage, pkgList, uidList);
6282 mConditionProviders.onPackagesChanged(removingPackage, pkgList, uidList);
Julia Reynolds996c7c12019-05-24 10:25:33 -04006283 preferencesChanged |= mPreferencesHelper.onPackagesChanged(
Julia Reynoldsb0405592018-11-26 17:01:13 -05006284 removingPackage, changeUserId, pkgList, uidList);
Julia Reynolds996c7c12019-05-24 10:25:33 -04006285 if (preferencesChanged) {
6286 handleSavePolicyFile();
6287 }
Julia Reynoldsb0405592018-11-26 17:01:13 -05006288 }
6289
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006290 protected class WorkerHandler extends Handler
Adam Lesinski182f73f2013-12-05 16:48:06 -08006291 {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006292 public WorkerHandler(Looper looper) {
6293 super(looper);
6294 }
6295
Adam Lesinski182f73f2013-12-05 16:48:06 -08006296 @Override
6297 public void handleMessage(Message msg)
6298 {
6299 switch (msg.what)
6300 {
Robert Carr997427342018-02-28 18:06:10 -08006301 case MESSAGE_DURATION_REACHED:
Julia Reynoldsb0405592018-11-26 17:01:13 -05006302 handleDurationReached((ToastRecord) msg.obj);
Robert Carr997427342018-02-28 18:06:10 -08006303 break;
6304 case MESSAGE_FINISH_TOKEN_TIMEOUT:
Julia Reynoldsb0405592018-11-26 17:01:13 -05006305 handleKillTokenTimeout((ToastRecord) msg.obj);
Adam Lesinski182f73f2013-12-05 16:48:06 -08006306 break;
Chris Wrenf9536642014-04-17 10:01:54 -04006307 case MESSAGE_SEND_RANKING_UPDATE:
6308 handleSendRankingUpdate();
6309 break;
John Spurlockd8afe3c2014-08-01 14:04:07 -04006310 case MESSAGE_LISTENER_HINTS_CHANGED:
6311 handleListenerHintsChanged(msg.arg1);
John Spurlock1fa865f2014-07-21 14:56:39 -04006312 break;
Christoph Studer85a384b2014-08-27 20:16:15 +02006313 case MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED:
6314 handleListenerInterruptionFilterChanged(msg.arg1);
6315 break;
Julia Reynoldsb0405592018-11-26 17:01:13 -05006316 case MESSAGE_ON_PACKAGE_CHANGED:
6317 SomeArgs args = (SomeArgs) msg.obj;
6318 handleOnPackageChanged((boolean) args.arg1, args.argi1, (String[]) args.arg2,
6319 (int[]) args.arg3);
6320 args.recycle();
6321 break;
Chris Wrenf9536642014-04-17 10:01:54 -04006322 }
6323 }
6324
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006325 protected void scheduleSendRankingUpdate() {
6326 if (!hasMessages(MESSAGE_SEND_RANKING_UPDATE)) {
6327 Message m = Message.obtain(this, MESSAGE_SEND_RANKING_UPDATE);
6328 sendMessage(m);
6329 }
6330 }
6331
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006332 protected void scheduleCancelNotification(CancelNotificationRunnable cancelRunnable) {
6333 if (!hasCallbacks(cancelRunnable)) {
6334 sendMessage(Message.obtain(this, cancelRunnable));
6335 }
6336 }
Julia Reynoldsb0405592018-11-26 17:01:13 -05006337
6338 protected void scheduleOnPackageChanged(boolean removingPackage, int changeUserId,
6339 String[] pkgList, int[] uidList) {
6340 SomeArgs args = SomeArgs.obtain();
6341 args.arg1 = removingPackage;
6342 args.argi1 = changeUserId;
6343 args.arg2 = pkgList;
6344 args.arg3 = uidList;
6345 sendMessage(Message.obtain(this, MESSAGE_ON_PACKAGE_CHANGED, args));
6346 }
Chris Wrenf9536642014-04-17 10:01:54 -04006347 }
6348
Chris Wren51017d02015-12-15 15:34:46 -05006349 private final class RankingHandlerWorker extends Handler implements RankingHandler
Chris Wrenf9536642014-04-17 10:01:54 -04006350 {
Chris Wren51017d02015-12-15 15:34:46 -05006351 public RankingHandlerWorker(Looper looper) {
Chris Wrenf9536642014-04-17 10:01:54 -04006352 super(looper);
6353 }
6354
6355 @Override
6356 public void handleMessage(Message msg) {
6357 switch (msg.what) {
6358 case MESSAGE_RECONSIDER_RANKING:
6359 handleRankingReconsideration(msg);
6360 break;
Chris Wren51017d02015-12-15 15:34:46 -05006361 case MESSAGE_RANKING_SORT:
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006362 handleRankingSort();
Chris Wren54bbef42014-07-09 18:37:56 -04006363 break;
Adam Lesinski182f73f2013-12-05 16:48:06 -08006364 }
6365 }
Chris Wren51017d02015-12-15 15:34:46 -05006366
Julia Reynoldseb3dca72017-07-11 10:39:58 -04006367 public void requestSort() {
Chris Wren51017d02015-12-15 15:34:46 -05006368 removeMessages(MESSAGE_RANKING_SORT);
Julia Reynolds22f02b32016-12-01 15:05:13 -05006369 Message msg = Message.obtain();
6370 msg.what = MESSAGE_RANKING_SORT;
Julia Reynolds22f02b32016-12-01 15:05:13 -05006371 sendMessage(msg);
Chris Wren51017d02015-12-15 15:34:46 -05006372 }
6373
6374 public void requestReconsideration(RankingReconsideration recon) {
6375 Message m = Message.obtain(this,
6376 NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
6377 long delay = recon.getDelay(TimeUnit.MILLISECONDS);
6378 sendMessageDelayed(m, delay);
6379 }
Adam Lesinski182f73f2013-12-05 16:48:06 -08006380 }
6381
Adam Lesinski182f73f2013-12-05 16:48:06 -08006382 // Notifications
6383 // ============================================================================
6384 static int clamp(int x, int low, int high) {
6385 return (x < low) ? low : ((x > high) ? high : x);
6386 }
6387
6388 void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
Eugene Suslad4128ec2017-12-04 19:48:41 +00006389 if (!mAccessibilityManager.isEnabled()) {
svetoslavganov75986cf2009-05-14 22:28:01 -07006390 return;
6391 }
6392
6393 AccessibilityEvent event =
6394 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
6395 event.setPackageName(packageName);
6396 event.setClassName(Notification.class.getName());
6397 event.setParcelableData(notification);
6398 CharSequence tickerText = notification.tickerText;
6399 if (!TextUtils.isEmpty(tickerText)) {
6400 event.getText().add(tickerText);
6401 }
6402
Julia Reynolds94187562017-10-10 13:58:49 -04006403 mAccessibilityManager.sendAccessibilityEvent(event);
svetoslavganov75986cf2009-05-14 22:28:01 -07006404 }
6405
Julia Reynolds0839c022017-06-15 15:24:01 -04006406 /**
6407 * Removes all NotificationsRecords with the same key as the given notification record
6408 * from both lists. Do not call this method while iterating over either list.
6409 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04006410 @GuardedBy("mNotificationLock")
Julia Reynolds0839c022017-06-15 15:24:01 -04006411 private boolean removeFromNotificationListsLocked(NotificationRecord r) {
6412 // Remove from both lists, either list could have a separate Record for what is
6413 // effectively the same notification.
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006414 boolean wasPosted = false;
6415 NotificationRecord recordInList = null;
Julia Reynolds0839c022017-06-15 15:24:01 -04006416 if ((recordInList = findNotificationByListLocked(mNotificationList, r.getKey()))
6417 != null) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006418 mNotificationList.remove(recordInList);
6419 mNotificationsByKey.remove(recordInList.sbn.getKey());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006420 wasPosted = true;
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006421 }
Geoffrey Pitsch27684152017-05-02 11:41:31 -04006422 while ((recordInList = findNotificationByListLocked(mEnqueuedNotifications, r.getKey()))
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006423 != null) {
6424 mEnqueuedNotifications.remove(recordInList);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006425 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006426 return wasPosted;
6427 }
6428
6429 @GuardedBy("mNotificationLock")
6430 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
Julia Reynolds359e9b12017-08-08 12:40:04 -04006431 boolean wasPosted, String listenerName) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08006432 cancelNotificationLocked(r, sendDelete, reason, -1, -1, wasPosted, listenerName);
6433 }
6434
6435 @GuardedBy("mNotificationLock")
6436 private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete, int reason,
6437 int rank, int count, boolean wasPosted, String listenerName) {
Julia Reynolds0839c022017-06-15 15:24:01 -04006438 final String canceledKey = r.getKey();
Julia Reynoldsc6b371b2016-06-14 08:31:03 -04006439
6440 // Record caller.
6441 recordCallerLocked(r);
6442
Julia Reynolds503ed942017-10-04 16:04:56 -04006443 if (r.getStats().getDismissalSurface() == NotificationStats.DISMISSAL_NOT_DISMISSED) {
6444 r.recordDismissalSurface(NotificationStats.DISMISSAL_OTHER);
6445 }
6446
Joe Onorato46439ce2010-11-19 13:56:21 -08006447 // tell the app
6448 if (sendDelete) {
Michal Karpinskid2075892019-04-17 16:01:10 +01006449 final PendingIntent deleteIntent = r.getNotification().deleteIntent;
6450 if (deleteIntent != null) {
Joe Onorato46439ce2010-11-19 13:56:21 -08006451 try {
Michal Karpinskid2075892019-04-17 16:01:10 +01006452 // make sure deleteIntent cannot be used to start activities from background
6453 LocalServices.getService(ActivityManagerInternal.class)
6454 .clearPendingIntentAllowBgActivityStarts(deleteIntent.getTarget(),
6455 WHITELIST_TOKEN);
6456 deleteIntent.send();
Joe Onorato46439ce2010-11-19 13:56:21 -08006457 } catch (PendingIntent.CanceledException ex) {
6458 // do nothing - there's no relevant way to recover, and
6459 // no reason to let this propagate
Daniel Sandler4f91efd2013-04-25 16:38:41 -04006460 Slog.w(TAG, "canceled PendingIntent for " + r.sbn.getPackageName(), ex);
Joe Onorato46439ce2010-11-19 13:56:21 -08006461 }
6462 }
6463 }
6464
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006465 // Only cancel these if this notification actually got to be posted.
6466 if (wasPosted) {
6467 // status bar
6468 if (r.getNotification().getSmallIcon() != null) {
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006469 if (reason != REASON_SNOOZED) {
6470 r.isCanceled = true;
6471 }
Beverly5a20a5e2018-03-06 15:02:44 -05006472 mListeners.notifyRemovedLocked(r, reason, r.getStats());
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006473 mHandler.post(new Runnable() {
6474 @Override
6475 public void run() {
6476 mGroupHelper.onNotificationRemoved(r.sbn);
6477 }
6478 });
6479 }
6480
6481 // sound
6482 if (canceledKey.equals(mSoundNotificationKey)) {
6483 mSoundNotificationKey = null;
6484 final long identity = Binder.clearCallingIdentity();
6485 try {
6486 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
6487 if (player != null) {
6488 player.stopAsync();
6489 }
6490 } catch (RemoteException e) {
6491 } finally {
6492 Binder.restoreCallingIdentity(identity);
Julia Reynolds8f488d32016-10-14 10:59:01 -04006493 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006494 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006495
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006496 // vibrate
6497 if (canceledKey.equals(mVibrateNotificationKey)) {
6498 mVibrateNotificationKey = null;
6499 long identity = Binder.clearCallingIdentity();
6500 try {
6501 mVibrator.cancel();
Jeff Sharkey098d5802012-04-26 17:30:34 -07006502 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006503 finally {
6504 Binder.restoreCallingIdentity(identity);
6505 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006507
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006508 // light
6509 mLights.remove(canceledKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006510 }
6511
Christoph Studer546bec82014-03-14 12:17:12 +01006512 // Record usage stats
Julia Reynoldse46bb372016-03-17 11:05:58 -04006513 // TODO: add unbundling stats?
Christoph Studer546bec82014-03-14 12:17:12 +01006514 switch (reason) {
Julia Reynoldsf619bc52017-03-17 08:32:23 -04006515 case REASON_CANCEL:
6516 case REASON_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01006517 case REASON_LISTENER_CANCEL:
6518 case REASON_LISTENER_CANCEL_ALL:
6519 mUsageStats.registerDismissedByUser(r);
6520 break;
Chris Wren9fa689f2015-11-20 16:44:53 -05006521 case REASON_APP_CANCEL:
6522 case REASON_APP_CANCEL_ALL:
Christoph Studer546bec82014-03-14 12:17:12 +01006523 mUsageStats.registerRemovedByApp(r);
6524 break;
Christoph Studer546bec82014-03-14 12:17:12 +01006525 }
6526
Christoph Studer265c1052014-07-23 17:14:33 +02006527 String groupKey = r.getGroupKey();
6528 NotificationRecord groupSummary = mSummaryByGroupKey.get(groupKey);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006529 if (groupSummary != null && groupSummary.getKey().equals(canceledKey)) {
Christoph Studer265c1052014-07-23 17:14:33 +02006530 mSummaryByGroupKey.remove(groupKey);
6531 }
Julia Reynoldseae43fb2016-05-09 12:42:58 -04006532 final ArrayMap<String, String> summaries = mAutobundledSummaries.get(r.sbn.getUserId());
6533 if (summaries != null && r.sbn.getKey().equals(summaries.get(r.sbn.getPackageName()))) {
6534 summaries.remove(r.sbn.getPackageName());
Julia Reynoldse46bb372016-03-17 11:05:58 -04006535 }
Christoph Studercef37cf2014-07-25 14:18:17 +02006536
Daniel Sandler23d7c702013-03-07 16:32:06 -05006537 // Save it for users of getHistoricalNotifications()
6538 mArchive.record(r.sbn);
Christoph Studer81e5b5f2014-10-22 17:19:56 +02006539
Chris Wren6650e572015-05-15 17:19:25 -04006540 final long now = System.currentTimeMillis();
Julia Reynolds3dfdde02018-10-08 09:17:56 -04006541 final LogMaker logMaker = r.getItemLogMaker()
Chris Wren9eb5e102017-01-26 13:15:06 -05006542 .setType(MetricsEvent.TYPE_DISMISS)
Dieter Hsud39f0d52018-04-14 02:08:30 +08006543 .setSubtype(reason);
6544 if (rank != -1 && count != -1) {
6545 logMaker.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, rank)
6546 .addTaggedData(MetricsEvent.NOTIFICATION_SHADE_COUNT, count);
6547 }
6548 MetricsLogger.action(logMaker);
Chris Wrene6ddb8a2015-05-27 15:21:00 -04006549 EventLogTags.writeNotificationCanceled(canceledKey, reason,
Dieter Hsud39f0d52018-04-14 02:08:30 +08006550 r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now),
6551 rank, count, listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006552 }
6553
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006554 @VisibleForTesting
6555 void updateUriPermissions(@Nullable NotificationRecord newRecord,
6556 @Nullable NotificationRecord oldRecord, String targetPkg, int targetUserId) {
6557 final String key = (newRecord != null) ? newRecord.getKey() : oldRecord.getKey();
6558 if (DBG) Slog.d(TAG, key + ": updating permissions");
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006559
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006560 final ArraySet<Uri> newUris = (newRecord != null) ? newRecord.getGrantableUris() : null;
6561 final ArraySet<Uri> oldUris = (oldRecord != null) ? oldRecord.getGrantableUris() : null;
6562
6563 // Shortcut when no Uris involved
6564 if (newUris == null && oldUris == null) {
6565 return;
6566 }
6567
6568 // Inherit any existing owner
6569 IBinder permissionOwner = null;
6570 if (newRecord != null && permissionOwner == null) {
6571 permissionOwner = newRecord.permissionOwner;
6572 }
6573 if (oldRecord != null && permissionOwner == null) {
6574 permissionOwner = oldRecord.permissionOwner;
6575 }
6576
6577 // If we have Uris to grant, but no owner yet, go create one
6578 if (newUris != null && permissionOwner == null) {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006579 if (DBG) Slog.d(TAG, key + ": creating owner");
6580 permissionOwner = mUgmInternal.newUriPermissionOwner("NOTIF:" + key);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006581 }
6582
6583 // If we have no Uris to grant, but an existing owner, go destroy it
6584 if (newUris == null && permissionOwner != null) {
6585 final long ident = Binder.clearCallingIdentity();
6586 try {
6587 if (DBG) Slog.d(TAG, key + ": destroying owner");
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006588 mUgmInternal.revokeUriPermissionFromOwner(permissionOwner, null, ~0,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006589 UserHandle.getUserId(oldRecord.getUid()));
6590 permissionOwner = null;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006591 } finally {
6592 Binder.restoreCallingIdentity(ident);
6593 }
6594 }
6595
6596 // Grant access to new Uris
6597 if (newUris != null && permissionOwner != null) {
6598 for (int i = 0; i < newUris.size(); i++) {
6599 final Uri uri = newUris.valueAt(i);
6600 if (oldUris == null || !oldUris.contains(uri)) {
6601 if (DBG) Slog.d(TAG, key + ": granting " + uri);
6602 grantUriPermission(permissionOwner, uri, newRecord.getUid(), targetPkg,
6603 targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006604 }
6605 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006606 }
6607
6608 // Revoke access to old Uris
6609 if (oldUris != null && permissionOwner != null) {
6610 for (int i = 0; i < oldUris.size(); i++) {
6611 final Uri uri = oldUris.valueAt(i);
6612 if (newUris == null || !newUris.contains(uri)) {
6613 if (DBG) Slog.d(TAG, key + ": revoking " + uri);
6614 revokeUriPermission(permissionOwner, uri, oldRecord.getUid());
6615 }
6616 }
6617 }
6618
6619 if (newRecord != null) {
6620 newRecord.permissionOwner = permissionOwner;
6621 }
6622 }
6623
6624 private void grantUriPermission(IBinder owner, Uri uri, int sourceUid, String targetPkg,
6625 int targetUserId) {
6626 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6627
6628 final long ident = Binder.clearCallingIdentity();
6629 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006630 mUgm.grantUriPermissionFromOwner(owner, sourceUid, targetPkg,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006631 ContentProvider.getUriWithoutUserId(uri),
6632 Intent.FLAG_GRANT_READ_URI_PERMISSION,
6633 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)),
6634 targetUserId);
6635 } catch (RemoteException ignored) {
6636 // Ignored because we're in same process
6637 } finally {
6638 Binder.restoreCallingIdentity(ident);
6639 }
6640 }
6641
6642 private void revokeUriPermission(IBinder owner, Uri uri, int sourceUid) {
6643 if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
6644
6645 final long ident = Binder.clearCallingIdentity();
6646 try {
Wale Ogunwale6d50dcc2018-07-21 23:00:40 -07006647 mUgmInternal.revokeUriPermissionFromOwner(
6648 owner,
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06006649 ContentProvider.getUriWithoutUserId(uri),
6650 Intent.FLAG_GRANT_READ_URI_PERMISSION,
6651 ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
Julia Reynoldse0d711f2017-09-01 08:50:47 -04006652 } finally {
6653 Binder.restoreCallingIdentity(ident);
6654 }
6655 }
6656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006657 /**
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07006658 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
Doug Zongkerab5c49c2009-12-04 10:31:43 -08006659 * and none of the {@code mustNotHaveFlags}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006660 */
John Spurlocke6a7d932014-03-13 12:29:00 -04006661 void cancelNotification(final int callingUid, final int callingPid,
6662 final String pkg, final String tag, final int id,
Svetoslav Ganov835835e2013-08-04 20:17:52 -07006663 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
John Spurlock7340fc82014-04-24 18:50:12 -04006664 final int userId, final int reason, final ManagedServiceInfo listener) {
Dieter Hsud39f0d52018-04-14 02:08:30 +08006665 cancelNotification(callingUid, callingPid, pkg, tag, id, mustHaveFlags, mustNotHaveFlags,
6666 sendDelete, userId, reason, -1 /* rank */, -1 /* count */, listener);
6667 }
6668
6669 /**
6670 * Cancels a notification ONLY if it has all of the {@code mustHaveFlags}
6671 * and none of the {@code mustNotHaveFlags}.
6672 */
6673 void cancelNotification(final int callingUid, final int callingPid,
6674 final String pkg, final String tag, final int id,
6675 final int mustHaveFlags, final int mustNotHaveFlags, final boolean sendDelete,
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006676 final int userId, final int reason, int rank, int count,
6677 final ManagedServiceInfo listener) {
Svetoslav Ganov835835e2013-08-04 20:17:52 -07006678 // In enqueueNotificationInternal notifications are added by scheduling the
6679 // work on the worker handler. Hence, we also schedule the cancel on this
6680 // handler to avoid a scenario where an add notification call followed by a
6681 // remove notification call ends up in not removing the notification.
Julia Reynoldsefcdff42018-08-09 09:42:56 -04006682 mHandler.scheduleCancelNotification(new CancelNotificationRunnable(callingUid, callingPid,
6683 pkg, tag, id, mustHaveFlags, mustNotHaveFlags, sendDelete, userId, reason, rank,
6684 count, listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006685 }
6686
6687 /**
Daniel Sandler321e9c52012-10-12 10:59:26 -07006688 * Determine whether the userId applies to the notification in question, either because
6689 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard).
6690 */
6691 private boolean notificationMatchesUserId(NotificationRecord r, int userId) {
6692 return
6693 // looking for USER_ALL notifications? match everything
6694 userId == UserHandle.USER_ALL
6695 // a notification sent to USER_ALL matches any query
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006696 || r.getUserId() == UserHandle.USER_ALL
Daniel Sandler321e9c52012-10-12 10:59:26 -07006697 // an exact user match
Daniel Sandlerfde19b12013-01-17 00:21:05 -05006698 || r.getUserId() == userId;
Daniel Sandler321e9c52012-10-12 10:59:26 -07006699 }
6700
6701 /**
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006702 * Determine whether the userId applies to the notification in question, either because
6703 * they match exactly, or one of them is USER_ALL (which is treated as a wildcard) or
Kenny Guy2a764942014-04-02 13:29:20 +01006704 * because it matches one of the users profiles.
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006705 */
Kenny Guy2a764942014-04-02 13:29:20 +01006706 private boolean notificationMatchesCurrentProfiles(NotificationRecord r, int userId) {
Kenny Guya263e4e2014-03-03 18:24:03 +00006707 return notificationMatchesUserId(r, userId)
John Spurlockb408e8e2014-04-23 21:12:45 -04006708 || mUserProfiles.isCurrentProfile(r.getUserId());
Kenny Guy3a7c4a52014-03-03 18:24:03 +00006709 }
6710
6711 /**
Julia Reynoldsef37f282016-02-12 09:11:27 -05006712 * Cancels all notifications from a given package that have all of the
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006713 * {@code mustHaveFlags}.
6714 */
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006715 void cancelAllNotificationsInt(int callingUid, int callingPid, String pkg, String channelId,
Julia Reynoldsb5e44b72016-08-16 15:00:25 -04006716 int mustHaveFlags, int mustNotHaveFlags, boolean doit, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006717 ManagedServiceInfo listener) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006718 mHandler.post(new Runnable() {
6719 @Override
6720 public void run() {
6721 String listenerName = listener == null ? null : listener.component.toShortString();
6722 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6723 pkg, userId, mustHaveFlags, mustNotHaveFlags, reason,
6724 listenerName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006725
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006726 // Why does this parameter exist? Do we actually want to execute the above if doit
6727 // is false?
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006728 if (!doit) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006729 return;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08006730 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006731
6732 synchronized (mNotificationLock) {
6733 FlagChecker flagChecker = (int flags) -> {
6734 if ((flags & mustHaveFlags) != mustHaveFlags) {
6735 return false;
6736 }
6737 if ((flags & mustNotHaveFlags) != 0) {
6738 return false;
6739 }
6740 return true;
6741 };
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006742 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6743 pkg, true /*nullPkgIndicatesUserSwitch*/, channelId, flagChecker,
6744 false /*includeCurrentProfiles*/, userId, false /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006745 listenerName, true /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006746 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6747 callingPid, pkg, true /*nullPkgIndicatesUserSwitch*/, channelId,
6748 flagChecker, false /*includeCurrentProfiles*/, userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006749 false /*sendDelete*/, reason, listenerName, false /* wasPosted */);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006750 mSnoozeHelper.cancel(userId, pkg);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006751 }
6752 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006753 });
6754 }
6755
6756 private interface FlagChecker {
6757 // Returns false if these flags do not pass the defined flag test.
6758 public boolean apply(int flags);
6759 }
6760
Julia Reynolds88860ce2017-06-01 16:55:49 -04006761 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006762 private void cancelAllNotificationsByListLocked(ArrayList<NotificationRecord> notificationList,
6763 int callingUid, int callingPid, String pkg, boolean nullPkgIndicatesUserSwitch,
6764 String channelId, FlagChecker flagChecker, boolean includeCurrentProfiles, int userId,
Julia Reynolds0839c022017-06-15 15:24:01 -04006765 boolean sendDelete, int reason, String listenerName, boolean wasPosted) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006766 ArrayList<NotificationRecord> canceledNotifications = null;
6767 for (int i = notificationList.size() - 1; i >= 0; --i) {
6768 NotificationRecord r = notificationList.get(i);
6769 if (includeCurrentProfiles) {
6770 if (!notificationMatchesCurrentProfiles(r, userId)) {
6771 continue;
6772 }
6773 } else if (!notificationMatchesUserId(r, userId)) {
6774 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006775 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006776 // Don't remove notifications to all, if there's no package name specified
6777 if (nullPkgIndicatesUserSwitch && pkg == null && r.getUserId() == UserHandle.USER_ALL) {
6778 continue;
6779 }
6780 if (!flagChecker.apply(r.getFlags())) {
6781 continue;
6782 }
6783 if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
6784 continue;
6785 }
6786 if (channelId != null && !channelId.equals(r.getChannel().getId())) {
6787 continue;
6788 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006789 if (canceledNotifications == null) {
6790 canceledNotifications = new ArrayList<>();
6791 }
Julia Reynolds0839c022017-06-15 15:24:01 -04006792 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006793 mNotificationsByKey.remove(r.getKey());
Julia Reynoldsfd4099d2018-08-21 11:06:06 -04006794 r.recordDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_NEUTRAL);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006795 canceledNotifications.add(r);
Julia Reynolds359e9b12017-08-08 12:40:04 -04006796 cancelNotificationLocked(r, sendDelete, reason, wasPosted, listenerName);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006797 }
6798 if (canceledNotifications != null) {
6799 final int M = canceledNotifications.size();
6800 for (int i = 0; i < M; i++) {
6801 cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006802 listenerName, false /* sendDelete */, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006803 }
6804 updateLightsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006805 }
6806 }
6807
Julia Reynolds50989772017-02-23 14:32:16 -05006808 void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006809 ManagedServiceInfo listener) {
Julia Reynolds79672302017-01-12 08:30:16 -05006810 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsa8b766f2017-03-07 16:30:21 -05006811 if (duration <= 0 && snoozeCriterionId == null || key == null) {
Julia Reynoldscf63ff12017-01-24 13:55:48 -05006812 return;
6813 }
Julia Reynolds520df6e2017-02-13 09:05:10 -05006814
Julia Reynolds79672302017-01-12 08:30:16 -05006815 if (DBG) {
Julia Reynolds50989772017-02-23 14:32:16 -05006816 Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
6817 snoozeCriterionId, listenerName));
Julia Reynolds79672302017-01-12 08:30:16 -05006818 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006819 // Needs to post so that it can cancel notifications not yet enqueued.
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006820 mHandler.post(new SnoozeNotificationRunnable(key, duration, snoozeCriterionId));
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006821 }
6822
6823 void unsnoozeNotificationInt(String key, ManagedServiceInfo listener) {
6824 String listenerName = listener == null ? null : listener.component.toShortString();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006825 if (DBG) {
6826 Slog.d(TAG, String.format("unsnooze event(%s, %s)", key, listenerName));
6827 }
Julia Reynolds79672302017-01-12 08:30:16 -05006828 mSnoozeHelper.repost(key);
Julia Reynoldsb62dad42018-11-26 16:33:02 -05006829 handleSavePolicyFile();
Julia Reynoldsb6c1f992016-11-22 09:26:46 -05006830 }
6831
Julia Reynolds88860ce2017-06-01 16:55:49 -04006832 @GuardedBy("mNotificationLock")
Adam Lesinski350159c2014-03-27 11:15:11 -07006833 void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
John Spurlock7340fc82014-04-24 18:50:12 -04006834 ManagedServiceInfo listener, boolean includeCurrentProfiles) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006835 mHandler.post(new Runnable() {
6836 @Override
6837 public void run() {
6838 synchronized (mNotificationLock) {
6839 String listenerName =
6840 listener == null ? null : listener.component.toShortString();
6841 EventLogTags.writeNotificationCancelAll(callingUid, callingPid,
6842 null, userId, 0, 0, reason, listenerName);
Christoph Studer546bec82014-03-14 12:17:12 +01006843
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006844 FlagChecker flagChecker = (int flags) -> {
Mady Mellor49b1bf12019-03-29 12:00:02 -07006845 int flagsToCheck = FLAG_ONGOING_EVENT | FLAG_NO_CLEAR;
6846 if (REASON_LISTENER_CANCEL_ALL == reason) {
6847 flagsToCheck |= FLAG_BUBBLE;
6848 }
6849 if ((flags & flagsToCheck) != 0) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006850 return false;
6851 }
6852 return true;
6853 };
6854
6855 cancelAllNotificationsByListLocked(mNotificationList, callingUid, callingPid,
6856 null, false /*nullPkgIndicatesUserSwitch*/, null, flagChecker,
6857 includeCurrentProfiles, userId, true /*sendDelete*/, reason,
Julia Reynolds0839c022017-06-15 15:24:01 -04006858 listenerName, true);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006859 cancelAllNotificationsByListLocked(mEnqueuedNotifications, callingUid,
6860 callingPid, null, false /*nullPkgIndicatesUserSwitch*/, null,
6861 flagChecker, includeCurrentProfiles, userId, true /*sendDelete*/,
Julia Reynolds0839c022017-06-15 15:24:01 -04006862 reason, listenerName, false);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006863 mSnoozeHelper.cancel(userId, includeCurrentProfiles);
Kenny Guya263e4e2014-03-03 18:24:03 +00006864 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006865 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006866 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006867 }
6868
Christoph Studere4ef156b2014-07-04 18:41:57 +02006869 // Warning: The caller is responsible for invoking updateLightsLocked().
Julia Reynolds88860ce2017-06-01 16:55:49 -04006870 @GuardedBy("mNotificationLock")
Christoph Studere4ef156b2014-07-04 18:41:57 +02006871 private void cancelGroupChildrenLocked(NotificationRecord r, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006872 String listenerName, boolean sendDelete, FlagChecker flagChecker) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006873 Notification n = r.getNotification();
Christoph Studer3f31f5d2014-07-31 16:55:32 +02006874 if (!n.isGroupSummary()) {
Christoph Studere4ef156b2014-07-04 18:41:57 +02006875 return;
6876 }
6877
6878 String pkg = r.sbn.getPackageName();
Christoph Studere4ef156b2014-07-04 18:41:57 +02006879
6880 if (pkg == null) {
Tony Mak180a9c42019-03-08 13:33:08 +00006881 if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey());
Christoph Studere4ef156b2014-07-04 18:41:57 +02006882 return;
6883 }
6884
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006885 cancelGroupChildrenByListLocked(mNotificationList, r, callingUid, callingPid, listenerName,
Beverly40239d92017-07-07 10:20:41 -04006886 sendDelete, true, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006887 cancelGroupChildrenByListLocked(mEnqueuedNotifications, r, callingUid, callingPid,
Beverly40239d92017-07-07 10:20:41 -04006888 listenerName, sendDelete, false, flagChecker);
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006889 }
6890
Julia Reynolds88860ce2017-06-01 16:55:49 -04006891 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006892 private void cancelGroupChildrenByListLocked(ArrayList<NotificationRecord> notificationList,
6893 NotificationRecord parentNotification, int callingUid, int callingPid,
Beverly40239d92017-07-07 10:20:41 -04006894 String listenerName, boolean sendDelete, boolean wasPosted, FlagChecker flagChecker) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006895 final String pkg = parentNotification.sbn.getPackageName();
6896 final int userId = parentNotification.getUserId();
6897 final int reason = REASON_GROUP_SUMMARY_CANCELED;
6898 for (int i = notificationList.size() - 1; i >= 0; i--) {
6899 final NotificationRecord childR = notificationList.get(i);
6900 final StatusBarNotification childSbn = childR.sbn;
Julia Reynoldse46bb372016-03-17 11:05:58 -04006901 if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006902 childR.getGroupKey().equals(parentNotification.getGroupKey())
Julia Reynoldse5c60452018-04-30 14:41:36 -04006903 && (childR.getFlags() & FLAG_FOREGROUND_SERVICE) == 0
Beverly40239d92017-07-07 10:20:41 -04006904 && (flagChecker == null || flagChecker.apply(childR.getFlags()))) {
Christoph Studer265c1052014-07-23 17:14:33 +02006905 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
6906 childSbn.getTag(), userId, 0, 0, reason, listenerName);
Julia Reynolds0839c022017-06-15 15:24:01 -04006907 notificationList.remove(i);
Julia Reynolds080361e2017-07-13 11:23:12 -04006908 mNotificationsByKey.remove(childR.getKey());
Julia Reynolds359e9b12017-08-08 12:40:04 -04006909 cancelNotificationLocked(childR, sendDelete, reason, wasPosted, listenerName);
Christoph Studere4ef156b2014-07-04 18:41:57 +02006910 }
6911 }
6912 }
6913
Julia Reynolds88860ce2017-06-01 16:55:49 -04006914 @GuardedBy("mNotificationLock")
Adam Lesinski182f73f2013-12-05 16:48:06 -08006915 void updateLightsLocked()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006916 {
The Android Open Source Project10592532009-03-18 17:39:46 -07006917 // handle notification lights
Chris Wren6054e612014-11-25 17:16:46 -05006918 NotificationRecord ledNotification = null;
6919 while (ledNotification == null && !mLights.isEmpty()) {
6920 final String owner = mLights.get(mLights.size() - 1);
6921 ledNotification = mNotificationsByKey.get(owner);
6922 if (ledNotification == null) {
6923 Slog.wtfStack(TAG, "LED Notification does not exist: " + owner);
6924 mLights.remove(owner);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006925 }
6926 }
Mike Lockwoodc22404a2009-12-02 11:15:02 -05006927
Mike Lockwood63b5ad92011-08-30 09:55:30 -04006928 // Don't flash while we are in a call or screen is on
Eric Laurent7412abc2019-07-12 18:26:29 -07006929 if (ledNotification == null || isInCall() || mScreenOn) {
Mike Lockwood3cb67a32009-11-27 14:25:58 -05006930 mNotificationLight.turnOff();
The Android Open Source Project10592532009-03-18 17:39:46 -07006931 } else {
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006932 NotificationRecord.Light light = ledNotification.getLight();
6933 if (light != null && mNotificationPulseEnabled) {
Mike Lockwood670f9322010-01-20 12:13:36 -05006934 // pulse repeatedly
Julia Reynoldsa33f5c42017-01-31 16:53:35 -05006935 mNotificationLight.setFlashing(light.color, Light.LIGHT_FLASH_TIMED,
6936 light.onMs, light.offMs);
Mike Lockwood670f9322010-01-20 12:13:36 -05006937 }
The Android Open Source Project10592532009-03-18 17:39:46 -07006938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006939 }
6940
Julia Reynolds88860ce2017-06-01 16:55:49 -04006941 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006942 @NonNull List<NotificationRecord> findGroupNotificationsLocked(String pkg,
6943 String groupKey, int userId) {
6944 List<NotificationRecord> records = new ArrayList<>();
6945 records.addAll(findGroupNotificationByListLocked(mNotificationList, pkg, groupKey, userId));
6946 records.addAll(
6947 findGroupNotificationByListLocked(mEnqueuedNotifications, pkg, groupKey, userId));
6948 return records;
6949 }
6950
6951
Julia Reynolds88860ce2017-06-01 16:55:49 -04006952 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006953 private @NonNull List<NotificationRecord> findGroupNotificationByListLocked(
6954 ArrayList<NotificationRecord> list, String pkg, String groupKey, int userId) {
6955 List<NotificationRecord> records = new ArrayList<>();
6956 final int len = list.size();
6957 for (int i = 0; i < len; i++) {
6958 NotificationRecord r = list.get(i);
6959 if (notificationMatchesUserId(r, userId) && r.getGroupKey().equals(groupKey)
6960 && r.sbn.getPackageName().equals(pkg)) {
6961 records.add(r);
6962 }
6963 }
6964 return records;
6965 }
6966
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006967 // Searches both enqueued and posted notifications by key.
6968 // TODO: need to combine a bunch of these getters with slightly different behavior.
6969 // TODO: Should enqueuing just add to mNotificationsByKey instead?
Julia Reynolds88860ce2017-06-01 16:55:49 -04006970 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006971 private NotificationRecord findNotificationByKeyLocked(String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006972 NotificationRecord r;
6973 if ((r = findNotificationByListLocked(mNotificationList, key)) != null) {
6974 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006975 }
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006976 if ((r = findNotificationByListLocked(mEnqueuedNotifications, key)) != null) {
6977 return r;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006978 }
6979 return null;
6980 }
6981
Julia Reynolds88860ce2017-06-01 16:55:49 -04006982 @GuardedBy("mNotificationLock")
Julia Reynoldsa78cdff2017-04-26 10:19:25 -04006983 NotificationRecord findNotificationLocked(String pkg, String tag, int id, int userId) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006984 NotificationRecord r;
6985 if ((r = findNotificationByListLocked(mNotificationList, pkg, tag, id, userId)) != null) {
6986 return r;
6987 }
6988 if ((r = findNotificationByListLocked(mEnqueuedNotifications, pkg, tag, id, userId))
6989 != null) {
6990 return r;
6991 }
6992 return null;
6993 }
6994
Julia Reynolds88860ce2017-06-01 16:55:49 -04006995 @GuardedBy("mNotificationLock")
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006996 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05006997 String pkg, String tag, int id, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006998 final int len = list.size();
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05006999 for (int i = 0; i < len; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007000 NotificationRecord r = list.get(i);
Vladimir Marko2526f332013-09-11 11:13:55 +01007001 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
7002 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007003 return r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007004 }
7005 }
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007006 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007007 }
7008
Julia Reynolds88860ce2017-06-01 16:55:49 -04007009 @GuardedBy("mNotificationLock")
Julia Reynolds564273f2018-09-13 15:53:11 -04007010 private List<NotificationRecord> findNotificationsByListLocked(
7011 ArrayList<NotificationRecord> list, String pkg, String tag, int id, int userId) {
7012 List<NotificationRecord> matching = new ArrayList<>();
7013 final int len = list.size();
7014 for (int i = 0; i < len; i++) {
7015 NotificationRecord r = list.get(i);
7016 if (notificationMatchesUserId(r, userId) && r.sbn.getId() == id &&
7017 TextUtils.equals(r.sbn.getTag(), tag) && r.sbn.getPackageName().equals(pkg)) {
7018 matching.add(r);
7019 }
7020 }
7021 return matching;
7022 }
7023
7024 @GuardedBy("mNotificationLock")
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05007025 private NotificationRecord findNotificationByListLocked(ArrayList<NotificationRecord> list,
Julia Reynolds88860ce2017-06-01 16:55:49 -04007026 String key) {
Geoffrey Pitschccc0b972017-02-15 10:52:26 -05007027 final int N = list.size();
7028 for (int i = 0; i < N; i++) {
7029 if (key.equals(list.get(i).getKey())) {
7030 return list.get(i);
7031 }
7032 }
7033 return null;
7034 }
7035
Julia Reynolds88860ce2017-06-01 16:55:49 -04007036 @GuardedBy("mNotificationLock")
Christoph Studer71f18fd2014-05-20 17:02:04 +02007037 int indexOfNotificationLocked(String key) {
Christoph Studerc5115552014-06-12 20:22:31 +02007038 final int N = mNotificationList.size();
7039 for (int i = 0; i < N; i++) {
7040 if (key.equals(mNotificationList.get(i).getKey())) {
7041 return i;
7042 }
Christoph Studer71f18fd2014-05-20 17:02:04 +02007043 }
Christoph Studerc5115552014-06-12 20:22:31 +02007044 return -1;
Christoph Studer71f18fd2014-05-20 17:02:04 +02007045 }
7046
Beverly5a20a5e2018-03-06 15:02:44 -05007047 @VisibleForTesting
7048 protected void hideNotificationsForPackages(String[] pkgs) {
7049 synchronized (mNotificationLock) {
7050 List<String> pkgList = Arrays.asList(pkgs);
7051 List<NotificationRecord> changedNotifications = new ArrayList<>();
7052 int numNotifications = mNotificationList.size();
7053 for (int i = 0; i < numNotifications; i++) {
7054 NotificationRecord rec = mNotificationList.get(i);
7055 if (pkgList.contains(rec.sbn.getPackageName())) {
7056 rec.setHidden(true);
7057 changedNotifications.add(rec);
7058 }
7059 }
7060
7061 mListeners.notifyHiddenLocked(changedNotifications);
7062 }
7063 }
7064
7065 @VisibleForTesting
7066 protected void unhideNotificationsForPackages(String[] pkgs) {
7067 synchronized (mNotificationLock) {
7068 List<String> pkgList = Arrays.asList(pkgs);
7069 List<NotificationRecord> changedNotifications = new ArrayList<>();
7070 int numNotifications = mNotificationList.size();
7071 for (int i = 0; i < numNotifications; i++) {
7072 NotificationRecord rec = mNotificationList.get(i);
7073 if (pkgList.contains(rec.sbn.getPackageName())) {
7074 rec.setHidden(false);
7075 changedNotifications.add(rec);
7076 }
7077 }
7078
7079 mListeners.notifyUnhiddenLocked(changedNotifications);
7080 }
7081 }
7082
Mike Lockwoodc22404a2009-12-02 11:15:02 -05007083 private void updateNotificationPulse() {
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007084 synchronized (mNotificationLock) {
Mike Lockwoodc22404a2009-12-02 11:15:02 -05007085 updateLightsLocked();
7086 }
7087 }
John Spurlocke677d712014-02-13 12:52:19 -05007088
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007089 protected boolean isCallingUidSystem() {
7090 final int uid = Binder.getCallingUid();
7091 return uid == Process.SYSTEM_UID;
7092 }
7093
7094 protected boolean isUidSystemOrPhone(int uid) {
John Spurlock7340fc82014-04-24 18:50:12 -04007095 final int appid = UserHandle.getAppId(uid);
7096 return (appid == Process.SYSTEM_UID || appid == Process.PHONE_UID || uid == 0);
7097 }
John Spurlockb408e8e2014-04-23 21:12:45 -04007098
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007099 // TODO: Most calls should probably move to isCallerSystem.
7100 protected boolean isCallerSystemOrPhone() {
7101 return isUidSystemOrPhone(Binder.getCallingUid());
John Spurlock7340fc82014-04-24 18:50:12 -04007102 }
7103
Julia Reynoldsb852e562017-06-06 16:14:18 -04007104 private void checkCallerIsSystemOrShell() {
7105 if (Binder.getCallingUid() == Process.SHELL_UID) {
7106 return;
7107 }
7108 checkCallerIsSystem();
7109 }
7110
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007111 private void checkCallerIsSystem() {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007112 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04007113 return;
7114 }
7115 throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
7116 }
7117
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007118 private void checkCallerIsSystemOrSystemUiOrShell() {
7119 if (Binder.getCallingUid() == Process.SHELL_UID) {
7120 return;
7121 }
7122 if (isCallerSystemOrPhone()) {
7123 return;
7124 }
7125 getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null);
7126 }
7127
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007128 private void checkCallerIsSystemOrSameApp(String pkg) {
Geoffrey Pitsch27684152017-05-02 11:41:31 -04007129 if (isCallerSystemOrPhone()) {
John Spurlock7340fc82014-04-24 18:50:12 -04007130 return;
7131 }
Julia Reynolds0cd1b782016-06-29 08:43:00 -04007132 checkCallerIsSameApp(pkg);
7133 }
7134
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007135 private boolean isCallerAndroid(String callingPkg, int uid) {
7136 return isUidSystemOrPhone(uid) && callingPkg != null
7137 && PackageManagerService.PLATFORM_PACKAGE_NAME.equals(callingPkg);
7138 }
7139
Brad Stenning8c991ea2018-07-31 13:33:01 -07007140 /**
7141 * Check if the notification is of a category type that is restricted to system use only,
7142 * if so throw SecurityException
7143 */
7144 private void checkRestrictedCategories(final Notification notification) {
7145 try {
7146 if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) {
7147 return;
7148 }
7149 } catch (RemoteException re) {
Tony Mak180a9c42019-03-08 13:33:08 +00007150 if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category "
Brad Stenning8c991ea2018-07-31 13:33:01 -07007151 + "restrictions check thus the check will be done anyway");
7152 }
7153 if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
7154 || Notification.CATEGORY_CAR_WARNING.equals(notification.category)
7155 || Notification.CATEGORY_CAR_INFORMATION.equals(notification.category)) {
7156 checkCallerIsSystem();
7157 }
7158 }
7159
Julia Reynoldsb6634872018-09-25 13:19:53 -04007160 @VisibleForTesting
Julia Reynolds268647a2018-10-25 16:54:27 -04007161 boolean isCallerInstantApp(int callingUid, int userId) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08007162 // System is always allowed to act for ephemeral apps.
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007163 if (isUidSystemOrPhone(callingUid)) {
Chad Brubaker6b68f102017-01-27 13:39:00 -08007164 return false;
7165 }
7166
Julia Reynolds86869c92019-06-21 10:45:06 -04007167 if (userId == UserHandle.USER_ALL) {
7168 userId = USER_SYSTEM;
7169 }
7170
Chad Brubaker6b68f102017-01-27 13:39:00 -08007171 try {
Julia Reynolds268647a2018-10-25 16:54:27 -04007172 final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
7173 if (pkgs == null) {
7174 throw new SecurityException("Unknown uid " + callingUid);
7175 }
7176 final String pkg = pkgs[0];
7177 mAppOps.checkPackage(callingUid, pkg);
7178
Julia Reynoldsb6634872018-09-25 13:19:53 -04007179 ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
Chad Brubaker6b68f102017-01-27 13:39:00 -08007180 if (ai == null) {
7181 throw new SecurityException("Unknown package " + pkg);
7182 }
7183 return ai.isInstantApp();
7184 } catch (RemoteException re) {
Julia Reynolds268647a2018-10-25 16:54:27 -04007185 throw new SecurityException("Unknown uid " + callingUid, re);
Chad Brubaker6b68f102017-01-27 13:39:00 -08007186 }
Chad Brubaker6b68f102017-01-27 13:39:00 -08007187 }
7188
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007189 private void checkCallerIsSameApp(String pkg) {
Julia Reynoldsb6634872018-09-25 13:19:53 -04007190 checkCallerIsSameApp(pkg, Binder.getCallingUid(), UserHandle.getCallingUserId());
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007191 }
7192
Julia Reynoldsb6634872018-09-25 13:19:53 -04007193 private void checkCallerIsSameApp(String pkg, int uid, int userId) {
John Spurlock7340fc82014-04-24 18:50:12 -04007194 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007195 ApplicationInfo ai = mPackageManager.getApplicationInfo(
Julia Reynoldsb6634872018-09-25 13:19:53 -04007196 pkg, 0, userId);
Dan Sandler09afc2e2014-07-18 14:29:20 -04007197 if (ai == null) {
7198 throw new SecurityException("Unknown package " + pkg);
7199 }
John Spurlock7340fc82014-04-24 18:50:12 -04007200 if (!UserHandle.isSameApp(ai.uid, uid)) {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007201 throw new SecurityException("Calling uid " + uid + " gave package "
John Spurlock7340fc82014-04-24 18:50:12 -04007202 + pkg + " which is owned by uid " + ai.uid);
7203 }
7204 } catch (RemoteException re) {
7205 throw new SecurityException("Unknown package " + pkg + "\n" + re);
7206 }
7207 }
7208
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007209 private boolean isCallerSameApp(String pkg) {
7210 try {
7211 checkCallerIsSameApp(pkg);
7212 return true;
7213 } catch (SecurityException e) {
7214 return false;
7215 }
7216 }
7217
Julia Reynoldsb6634872018-09-25 13:19:53 -04007218 private boolean isCallerSameApp(String pkg, int uid, int userId) {
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007219 try {
Julia Reynoldsb6634872018-09-25 13:19:53 -04007220 checkCallerIsSameApp(pkg, uid, userId);
Julia Reynoldsa7ba45a2018-08-29 09:07:52 -04007221 return true;
7222 } catch (SecurityException e) {
7223 return false;
7224 }
7225 }
7226
John Spurlock32fe4c62014-10-02 12:16:02 -04007227 private static String callStateToString(int state) {
7228 switch (state) {
7229 case TelephonyManager.CALL_STATE_IDLE: return "CALL_STATE_IDLE";
7230 case TelephonyManager.CALL_STATE_RINGING: return "CALL_STATE_RINGING";
7231 case TelephonyManager.CALL_STATE_OFFHOOK: return "CALL_STATE_OFFHOOK";
7232 default: return "CALL_STATE_UNKNOWN_" + state;
7233 }
7234 }
7235
7236 private void listenForCallState() {
Jayachandran C16dce222019-11-15 15:42:01 -08007237 getContext().getSystemService(TelephonyManager.class).listen(new PhoneStateListener() {
John Spurlock32fe4c62014-10-02 12:16:02 -04007238 @Override
7239 public void onCallStateChanged(int state, String incomingNumber) {
7240 if (mCallState == state) return;
7241 if (DBG) Slog.d(TAG, "Call state changed: " + callStateToString(state));
7242 mCallState = state;
7243 }
7244 }, PhoneStateListener.LISTEN_CALL_STATE);
7245 }
7246
Christoph Studer05ad4822014-05-16 14:16:03 +02007247 /**
7248 * Generates a NotificationRankingUpdate from 'sbns', considering only
7249 * notifications visible to the given listener.
7250 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007251 @GuardedBy("mNotificationLock")
Chris Wren333a61c2014-05-28 16:40:57 -04007252 private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) {
Chris Wren333a61c2014-05-28 16:40:57 -04007253 final int N = mNotificationList.size();
Dan Sandlerba666f82019-01-29 13:58:52 -05007254 final ArrayList<NotificationListenerService.Ranking> rankings = new ArrayList<>();
7255
Chris Wren333a61c2014-05-28 16:40:57 -04007256 for (int i = 0; i < N; i++) {
7257 NotificationRecord record = mNotificationList.get(i);
Christoph Studercef37cf2014-07-25 14:18:17 +02007258 if (!isVisibleToListener(record.sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007259 continue;
7260 }
Chris Wrenbdf33762015-12-04 15:50:51 -05007261 final String key = record.sbn.getKey();
Dan Sandlerba666f82019-01-29 13:58:52 -05007262 final NotificationListenerService.Ranking ranking =
7263 new NotificationListenerService.Ranking();
7264 ranking.populate(
7265 key,
7266 rankings.size(),
7267 !record.isIntercepted(),
7268 record.getPackageVisibilityOverride(),
7269 record.getSuppressedVisualEffects(),
7270 record.getImportance(),
7271 record.getImportanceExplanation(),
7272 record.sbn.getOverrideGroupKey(),
7273 record.getChannel(),
7274 record.getPeopleOverride(),
7275 record.getSnoozeCriteria(),
7276 record.canShowBadge(),
7277 record.getUserSentiment(),
7278 record.isHidden(),
7279 record.getLastAudiblyAlertedMs(),
7280 record.getSound() != null || record.getVibration() != null,
7281 record.getSystemGeneratedSmartActions(),
7282 record.getSmartReplies(),
7283 record.canBubble()
7284 );
7285 rankings.add(ranking);
7286 }
Julia Reynoldsf612869ae2015-11-05 16:48:55 -05007287
Dan Sandlerba666f82019-01-29 13:58:52 -05007288 return new NotificationRankingUpdate(
7289 rankings.toArray(new NotificationListenerService.Ranking[0]));
Christoph Studer05ad4822014-05-16 14:16:03 +02007290 }
7291
Julia Reynoldsda781472017-04-12 09:41:16 -04007292 boolean hasCompanionDevice(ManagedServiceInfo info) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007293 if (mCompanionManager == null) {
Julia Reynolds727a7282017-04-13 10:54:01 -04007294 mCompanionManager = getCompanionManager();
7295 }
7296 // Companion mgr doesn't exist on all device types
7297 if (mCompanionManager == null) {
7298 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007299 }
Julia Reynoldsda781472017-04-12 09:41:16 -04007300 long identity = Binder.clearCallingIdentity();
7301 try {
7302 List<String> associations = mCompanionManager.getAssociations(
7303 info.component.getPackageName(), info.userid);
7304 if (!ArrayUtils.isEmpty(associations)) {
7305 return true;
7306 }
7307 } catch (SecurityException se) {
7308 // Not a privileged listener
7309 } catch (RemoteException re) {
7310 Slog.e(TAG, "Cannot reach companion device service", re);
7311 } catch (Exception e) {
7312 Slog.e(TAG, "Cannot verify listener " + info, e);
7313 } finally {
7314 Binder.restoreCallingIdentity(identity);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007315 }
Julia Reynoldsda781472017-04-12 09:41:16 -04007316 return false;
Julia Reynolds73ed76b2017-04-04 17:04:38 -04007317 }
7318
Julia Reynolds727a7282017-04-13 10:54:01 -04007319 protected ICompanionDeviceManager getCompanionManager() {
7320 return ICompanionDeviceManager.Stub.asInterface(
7321 ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE));
7322 }
7323
Christoph Studercef37cf2014-07-25 14:18:17 +02007324 private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
7325 if (!listener.enabledAndUserMatches(sbn.getUserId())) {
7326 return false;
7327 }
Justin Koh8d11a5a2014-08-04 18:29:49 -07007328 // TODO: remove this for older listeners.
Christoph Studercef37cf2014-07-25 14:18:17 +02007329 return true;
7330 }
7331
Andrei Stingaceanu355b2322016-02-12 16:43:51 +00007332 private boolean isPackageSuspendedForUser(String pkg, int uid) {
Beverly2be7a052018-03-27 11:37:58 -04007333 final long identity = Binder.clearCallingIdentity();
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007334 int userId = UserHandle.getUserId(uid);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007335 try {
Geoffrey Pitsche75a66e2016-11-22 11:12:11 -05007336 return mPackageManager.isPackageSuspendedForUser(pkg, userId);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007337 } catch (RemoteException re) {
7338 throw new SecurityException("Could not talk to package manager service");
Andrei Stingaceanuefc4a342016-03-22 14:43:01 +00007339 } catch (IllegalArgumentException ex) {
7340 // Package not found.
7341 return false;
Beverly2be7a052018-03-27 11:37:58 -04007342 } finally {
7343 Binder.restoreCallingIdentity(identity);
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007344 }
Andrei Stingaceanu0122f6512016-01-22 15:33:03 +00007345 }
7346
Kristian Monsen30f59b22018-04-09 10:27:16 +02007347 @VisibleForTesting
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007348 boolean canUseManagedServices(String pkg, Integer userId, String requiredPermission) {
Kristian Monsen30f59b22018-04-09 10:27:16 +02007349 boolean canUseManagedServices = !mActivityManager.isLowRamDevice()
Julia Reynoldse1816412017-10-24 10:39:11 -04007350 || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
Kristian Monsen30f59b22018-04-09 10:27:16 +02007351
7352 for (String whitelisted : getContext().getResources().getStringArray(
7353 R.array.config_allowedManagedServicesOnLowRamDevices)) {
7354 if (whitelisted.equals(pkg)) {
7355 canUseManagedServices = true;
7356 }
7357 }
7358
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007359 if (requiredPermission != null) {
7360 try {
7361 if (mPackageManager.checkPermission(requiredPermission, pkg, userId)
7362 != PackageManager.PERMISSION_GRANTED) {
7363 canUseManagedServices = false;
7364 }
7365 } catch (RemoteException e) {
Tony Mak180a9c42019-03-08 13:33:08 +00007366 Slog.e(TAG, "can't talk to pm", e);
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007367 }
7368 }
7369
Kristian Monsen30f59b22018-04-09 10:27:16 +02007370 return canUseManagedServices;
Julia Reynoldse1816412017-10-24 10:39:11 -04007371 }
7372
Chris Wren47633422016-01-22 09:56:59 -05007373 private class TrimCache {
7374 StatusBarNotification heavy;
7375 StatusBarNotification sbnClone;
7376 StatusBarNotification sbnCloneLight;
7377
7378 TrimCache(StatusBarNotification sbn) {
7379 heavy = sbn;
7380 }
7381
7382 StatusBarNotification ForListener(ManagedServiceInfo info) {
7383 if (mListeners.getOnNotificationPostedTrim(info) == TRIM_LIGHT) {
7384 if (sbnCloneLight == null) {
7385 sbnCloneLight = heavy.cloneLight();
7386 }
7387 return sbnCloneLight;
7388 } else {
7389 if (sbnClone == null) {
7390 sbnClone = heavy.clone();
7391 }
7392 return sbnClone;
7393 }
7394 }
7395 }
7396
Eric Laurent7412abc2019-07-12 18:26:29 -07007397 private boolean isInCall() {
7398 if (mInCallStateOffHook) {
7399 return true;
7400 }
7401 int audioMode = mAudioManager.getMode();
7402 if (audioMode == AudioManager.MODE_IN_CALL
7403 || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
7404 return true;
7405 }
7406 return false;
7407 }
7408
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007409 public class NotificationAssistants extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007410 static final String TAG_ENABLED_NOTIFICATION_ASSISTANTS = "enabled_assistants";
Chris Wren51017d02015-12-15 15:34:46 -05007411
Tony Mak9a3c1f12019-03-04 16:04:42 +00007412 private static final String ATT_USER_SET = "user_set";
Julia Reynolds54c5fd12019-05-20 12:56:27 -04007413 private static final String TAG_ALLOWED_ADJUSTMENT_TYPES = "q_allowed_adjustments";
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007414 private static final String ATT_TYPES = "types";
Tony Mak9a3c1f12019-03-04 16:04:42 +00007415
7416 private final Object mLock = new Object();
7417
7418 @GuardedBy("mLock")
7419 private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007420 private Set<String> mAllowedAdjustments = new ArraySet<>();
Tony Mak9a3c1f12019-03-04 16:04:42 +00007421
Julia Reynolds7380d872018-01-12 10:28:26 -05007422 public NotificationAssistants(Context context, Object lock, UserProfiles up,
7423 IPackageManager pm) {
7424 super(context, lock, up, pm);
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007425
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007426 // Add all default allowed adjustment types. Will be overwritten by values in xml,
7427 // if they exist
7428 for (int i = 0; i < DEFAULT_ALLOWED_ADJUSTMENTS.length; i++) {
7429 mAllowedAdjustments.add(DEFAULT_ALLOWED_ADJUSTMENTS[i]);
7430 }
Chris Wren51017d02015-12-15 15:34:46 -05007431 }
7432
7433 @Override
7434 protected Config getConfig() {
7435 Config c = new Config();
Julia Reynolds503ed942017-10-04 16:04:56 -04007436 c.caption = "notification assistant";
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007437 c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04007438 c.xmlTag = TAG_ENABLED_NOTIFICATION_ASSISTANTS;
Julia Reynolds77b2cc92016-11-08 14:41:09 -05007439 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
7440 c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
Chris Wren51017d02015-12-15 15:34:46 -05007441 c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
Chris Wrene0ba7eb2016-03-04 17:30:43 -05007442 c.clientLabel = R.string.notification_ranker_binding_label;
Chris Wren51017d02015-12-15 15:34:46 -05007443 return c;
7444 }
7445
7446 @Override
7447 protected IInterface asInterface(IBinder binder) {
7448 return INotificationListener.Stub.asInterface(binder);
7449 }
7450
7451 @Override
7452 protected boolean checkType(IInterface service) {
7453 return service instanceof INotificationListener;
7454 }
7455
7456 @Override
7457 protected void onServiceAdded(ManagedServiceInfo info) {
7458 mListeners.registerGuestService(info);
7459 }
7460
7461 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04007462 @GuardedBy("mNotificationLock")
Chris Wren51017d02015-12-15 15:34:46 -05007463 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
7464 mListeners.unregisterService(removed.service, removed.userid);
7465 }
Chris Wren47633422016-01-22 09:56:59 -05007466
Julia Reynoldsef934fd2018-02-01 14:39:17 -05007467 @Override
7468 public void onUserUnlocked(int user) {
7469 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04007470 // force rebind the assistant, as it might be keeping its own state in user locked
7471 // storage
7472 rebindServices(true, user);
Julia Reynoldsef934fd2018-02-01 14:39:17 -05007473 }
7474
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007475 @Override
7476 protected String getRequiredPermission() {
Julia Reynoldscbc45e72019-03-07 12:31:52 -05007477 // only signature/privileged apps can be bound.
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007478 return android.Manifest.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE;
7479 }
7480
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007481 @Override
7482 protected void writeExtraXmlTags(XmlSerializer out) throws IOException {
7483 synchronized (mLock) {
7484 out.startTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
7485 out.attribute(null, ATT_TYPES, TextUtils.join(",", mAllowedAdjustments));
7486 out.endTag(null, TAG_ALLOWED_ADJUSTMENT_TYPES);
7487 }
7488 }
7489
7490 @Override
7491 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {
7492 if (TAG_ALLOWED_ADJUSTMENT_TYPES.equals(tag)) {
7493 final String types = XmlUtils.readStringAttribute(parser, ATT_TYPES);
Julia Reynolds25692c42019-05-03 15:01:24 -04007494 synchronized (mLock) {
7495 mAllowedAdjustments.clear();
7496 if (!TextUtils.isEmpty(types)) {
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007497 mAllowedAdjustments.addAll(Arrays.asList(types.split(",")));
7498 }
7499 }
7500 }
7501 }
7502
7503 protected void allowAdjustmentType(String type) {
7504 synchronized (mLock) {
7505 mAllowedAdjustments.add(type);
7506 }
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007507 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7508 mHandler.post(() -> notifyCapabilitiesChanged(info));
7509 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007510 }
7511
7512 protected void disallowAdjustmentType(String type) {
7513 synchronized (mLock) {
7514 mAllowedAdjustments.remove(type);
7515 }
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007516 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7517 mHandler.post(() -> notifyCapabilitiesChanged(info));
7518 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007519 }
7520
Julia Reynolds088c4482019-04-10 12:43:27 -04007521 protected List<String> getAllowedAssistantAdjustments() {
Julia Reynoldsad6dd352019-03-07 16:46:22 -05007522 synchronized (mLock) {
7523 List<String> types = new ArrayList<>();
7524 types.addAll(mAllowedAdjustments);
7525 return types;
7526 }
7527 }
7528
Julia Reynolds418a8ff2019-03-21 10:45:10 -04007529 protected boolean isAdjustmentAllowed(String type) {
7530 synchronized (mLock) {
7531 return mAllowedAdjustments.contains(type);
7532 }
7533 }
7534
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04007535 protected void onNotificationsSeenLocked(ArrayList<NotificationRecord> records) {
7536 // There should be only one, but it's a list, so while we enforce
7537 // singularity elsewhere, we keep it general here, to avoid surprises.
7538 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7539 ArrayList<String> keys = new ArrayList<>(records.size());
7540 for (NotificationRecord r : records) {
7541 boolean sbnVisible = isVisibleToListener(r.sbn, info)
7542 && info.isSameUser(r.getUserId());
7543 if (sbnVisible) {
7544 keys.add(r.getKey());
7545 }
7546 }
7547
7548 if (!keys.isEmpty()) {
7549 mHandler.post(() -> notifySeen(info, keys));
7550 }
7551 }
7552 }
7553
Tony Mak9a3c1f12019-03-04 16:04:42 +00007554 boolean hasUserSet(int userId) {
7555 synchronized (mLock) {
7556 return mUserSetMap.getOrDefault(userId, false);
7557 }
7558 }
7559
7560 void setUserSet(int userId, boolean set) {
7561 synchronized (mLock) {
7562 mUserSetMap.put(userId, set);
7563 }
7564 }
7565
7566 @Override
7567 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {
7568 out.attribute(null, ATT_USER_SET, Boolean.toString(hasUserSet(userId)));
7569 }
7570
7571 @Override
7572 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
7573 throws IOException {
7574 boolean userSet = XmlUtils.readBooleanAttribute(parser, ATT_USER_SET, false);
7575 setUserSet(userId, userSet);
7576 }
7577
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007578 private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
7579 final INotificationListener assistant = (INotificationListener) info.service;
7580 try {
Julia Reynolds088c4482019-04-10 12:43:27 -04007581 assistant.onAllowedAdjustmentsChanged();
Julia Reynoldsdc6adc62019-04-08 10:35:40 -04007582 } catch (RemoteException ex) {
7583 Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
7584 }
7585 }
7586
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04007587 private void notifySeen(final ManagedServiceInfo info,
7588 final ArrayList<String> keys) {
7589 final INotificationListener assistant = (INotificationListener) info.service;
7590 try {
7591 assistant.onNotificationsSeen(keys);
7592 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007593 Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
Julia Reynolds6a63d1b2018-08-14 16:59:33 -04007594 }
7595 }
7596
Tony Makeda84a72018-11-19 17:01:32 +00007597 @GuardedBy("mNotificationLock")
7598 private void onNotificationEnqueuedLocked(final NotificationRecord r) {
Tony Mak180a9c42019-03-08 13:33:08 +00007599 final boolean debug = isVerboseLogEnabled();
7600 if (debug) {
7601 Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]");
7602 }
Chris Wren47633422016-01-22 09:56:59 -05007603 final StatusBarNotification sbn = r.sbn;
Tony Makeda84a72018-11-19 17:01:32 +00007604 notifyAssistantLocked(
7605 sbn,
7606 true /* sameUserOnly */,
7607 (assistant, sbnHolder) -> {
7608 try {
Tony Mak180a9c42019-03-08 13:33:08 +00007609 if (debug) {
7610 Slog.v(TAG,
7611 "calling onNotificationEnqueuedWithChannel " + sbnHolder);
7612 }
Tony Makeda84a72018-11-19 17:01:32 +00007613 assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel());
7614 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007615 Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
Tony Makeda84a72018-11-19 17:01:32 +00007616 }
7617 });
Chris Wren47633422016-01-22 09:56:59 -05007618 }
7619
Tony Makeda84a72018-11-19 17:01:32 +00007620 @GuardedBy("mNotificationLock")
7621 void notifyAssistantExpansionChangedLocked(
7622 final StatusBarNotification sbn,
7623 final boolean isUserAction,
7624 final boolean isExpanded) {
7625 final String key = sbn.getKey();
7626 notifyAssistantLocked(
7627 sbn,
7628 false /* sameUserOnly */,
7629 (assistant, sbnHolder) -> {
7630 try {
7631 assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
7632 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007633 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
Tony Makeda84a72018-11-19 17:01:32 +00007634 }
7635 });
Chris Wren47633422016-01-22 09:56:59 -05007636 }
7637
Tony Makeda84a72018-11-19 17:01:32 +00007638 @GuardedBy("mNotificationLock")
7639 void notifyAssistantNotificationDirectReplyLocked(
7640 final StatusBarNotification sbn) {
7641 final String key = sbn.getKey();
7642 notifyAssistantLocked(
7643 sbn,
7644 false /* sameUserOnly */,
7645 (assistant, sbnHolder) -> {
7646 try {
7647 assistant.onNotificationDirectReply(key);
7648 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007649 Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
Tony Makeda84a72018-11-19 17:01:32 +00007650 }
7651 });
7652 }
7653
Tony Mak29996702018-11-26 16:23:34 +00007654 @GuardedBy("mNotificationLock")
7655 void notifyAssistantSuggestedReplySent(
7656 final StatusBarNotification sbn, CharSequence reply, boolean generatedByAssistant) {
7657 final String key = sbn.getKey();
7658 notifyAssistantLocked(
7659 sbn,
7660 false /* sameUserOnly */,
7661 (assistant, sbnHolder) -> {
7662 try {
7663 assistant.onSuggestedReplySent(
7664 key,
7665 reply,
7666 generatedByAssistant
7667 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7668 : NotificationAssistantService.SOURCE_FROM_APP);
7669 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007670 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
Tony Mak29996702018-11-26 16:23:34 +00007671 }
7672 });
7673 }
7674
Tony Mak7d4b3a52018-11-27 17:29:36 +00007675 @GuardedBy("mNotificationLock")
7676 void notifyAssistantActionClicked(
7677 final StatusBarNotification sbn, int actionIndex, Notification.Action action,
7678 boolean generatedByAssistant) {
7679 final String key = sbn.getKey();
7680 notifyAssistantLocked(
7681 sbn,
7682 false /* sameUserOnly */,
7683 (assistant, sbnHolder) -> {
7684 try {
7685 assistant.onActionClicked(
7686 key,
7687 action,
7688 generatedByAssistant
7689 ? NotificationAssistantService.SOURCE_FROM_ASSISTANT
7690 : NotificationAssistantService.SOURCE_FROM_APP);
7691 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007692 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
Tony Mak7d4b3a52018-11-27 17:29:36 +00007693 }
7694 });
7695 }
Tony Makeda84a72018-11-19 17:01:32 +00007696
Julia Reynolds79672302017-01-12 08:30:16 -05007697 /**
7698 * asynchronously notify the assistant that a notification has been snoozed until a
7699 * context
7700 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007701 @GuardedBy("mNotificationLock")
Tony Makeda84a72018-11-19 17:01:32 +00007702 private void notifyAssistantSnoozedLocked(
7703 final StatusBarNotification sbn, final String snoozeCriterionId) {
7704 notifyAssistantLocked(
7705 sbn,
7706 false /* sameUserOnly */,
7707 (assistant, sbnHolder) -> {
Julia Reynolds79672302017-01-12 08:30:16 -05007708 try {
7709 assistant.onNotificationSnoozedUntilContext(
7710 sbnHolder, snoozeCriterionId);
7711 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007712 Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
Julia Reynolds79672302017-01-12 08:30:16 -05007713 }
Tony Makeda84a72018-11-19 17:01:32 +00007714 });
7715 }
7716
7717 /**
7718 * Notifies the assistant something about the specified notification, only assistant
7719 * that is visible to the notification will be notified.
7720 *
7721 * @param sbn the notification object that the update is about.
7722 * @param sameUserOnly should the update be sent to the assistant in the same user only.
7723 * @param callback the callback that provides the assistant to be notified, executed
7724 * in WorkerHandler.
7725 */
7726 @GuardedBy("mNotificationLock")
7727 private void notifyAssistantLocked(
7728 final StatusBarNotification sbn,
7729 boolean sameUserOnly,
7730 BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
7731 TrimCache trimCache = new TrimCache(sbn);
7732 // There should be only one, but it's a list, so while we enforce
7733 // singularity elsewhere, we keep it general here, to avoid surprises.
Tony Mak180a9c42019-03-08 13:33:08 +00007734
7735 final boolean debug = isVerboseLogEnabled();
7736 if (debug) {
7737 Slog.v(TAG,
7738 "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = ["
7739 + sameUserOnly + "], callback = [" + callback + "]");
7740 }
Tony Makeda84a72018-11-19 17:01:32 +00007741 for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
7742 boolean sbnVisible = isVisibleToListener(sbn, info)
7743 && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
Tony Mak180a9c42019-03-08 13:33:08 +00007744 if (debug) {
7745 Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
7746 }
Tony Makeda84a72018-11-19 17:01:32 +00007747 if (!sbnVisible) {
7748 continue;
7749 }
7750 final INotificationListener assistant = (INotificationListener) info.service;
7751 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
7752 final StatusBarNotificationHolder sbnHolder =
7753 new StatusBarNotificationHolder(sbnToPost);
7754 mHandler.post(() -> callback.accept(assistant, sbnHolder));
Julia Reynolds79672302017-01-12 08:30:16 -05007755 }
7756 }
7757
Chris Wren47633422016-01-22 09:56:59 -05007758 public boolean isEnabled() {
Julia Reynolds00314d92017-04-14 10:01:24 -04007759 return !getServices().isEmpty();
Chris Wren47633422016-01-22 09:56:59 -05007760 }
Julia Reynolds7380d872018-01-12 10:28:26 -05007761
Tony Mak9a3c1f12019-03-04 16:04:42 +00007762 protected void resetDefaultAssistantsIfNecessary() {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04007763 final List<UserInfo> activeUsers = mUm.getUsers(true);
7764 for (UserInfo userInfo : activeUsers) {
7765 int userId = userInfo.getUserHandle().getIdentifier();
Tony Mak9a3c1f12019-03-04 16:04:42 +00007766 if (!hasUserSet(userId)) {
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04007767 Slog.d(TAG, "Approving default notification assistant for user " + userId);
Tony Mak9a3c1f12019-03-04 16:04:42 +00007768 setDefaultAssistantForUser(userId);
Julia Reynoldsd6d5a592018-04-02 11:03:32 -04007769 }
Julia Reynolds7380d872018-01-12 10:28:26 -05007770 }
7771 }
Fabian Kozynskid9425662019-01-29 13:08:30 -05007772
7773 @Override
7774 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
7775 boolean isPrimary, boolean enabled) {
7776 // Ensures that only one component is enabled at a time
7777 if (enabled) {
7778 List<ComponentName> allowedComponents = getAllowedComponents(userId);
7779 if (!allowedComponents.isEmpty()) {
7780 ComponentName currentComponent = CollectionUtils.firstOrNull(allowedComponents);
7781 if (currentComponent.flattenToString().equals(pkgOrComponent)) return;
Tony Mak9a3c1f12019-03-04 16:04:42 +00007782 setNotificationAssistantAccessGrantedForUserInternal(
7783 currentComponent, userId, false);
Fabian Kozynskid9425662019-01-29 13:08:30 -05007784 }
7785 }
7786 super.setPackageOrComponentEnabled(pkgOrComponent, userId, isPrimary, enabled);
7787 }
Tony Mak9a3c1f12019-03-04 16:04:42 +00007788
7789 @Override
7790 public void dump(PrintWriter pw, DumpFilter filter) {
7791 super.dump(pw, filter);
7792 pw.println(" Has user set:");
7793 synchronized (mLock) {
7794 Set<Integer> userIds = mUserSetMap.keySet();
7795 for (int userId : userIds) {
7796 pw.println(" userId=" + userId + " value=" + mUserSetMap.get(userId));
7797 }
7798 }
7799 }
Tony Mak180a9c42019-03-08 13:33:08 +00007800
7801 private boolean isVerboseLogEnabled() {
7802 return Log.isLoggable("notification_assistant", Log.VERBOSE);
7803 }
Chris Wren51017d02015-12-15 15:34:46 -05007804 }
7805
John Spurlock7340fc82014-04-24 18:50:12 -04007806 public class NotificationListeners extends ManagedServices {
Julia Reynoldsb852e562017-06-06 16:14:18 -04007807 static final String TAG_ENABLED_NOTIFICATION_LISTENERS = "enabled_listeners";
John Spurlock7340fc82014-04-24 18:50:12 -04007808
Christoph Studerb82bc782014-08-20 14:29:43 +02007809 private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
7810
Julia Reynoldsb852e562017-06-06 16:14:18 -04007811 public NotificationListeners(IPackageManager pm) {
7812 super(getContext(), mNotificationLock, mUserProfiles, pm);
7813
John Spurlock7340fc82014-04-24 18:50:12 -04007814 }
7815
7816 @Override
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07007817 protected int getBindFlags() {
Amith Yamasani5016a782019-06-17 16:20:24 -07007818 // Most of the same flags as the base, but also add BIND_NOT_PERCEPTIBLE
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07007819 // because too many 3P apps could be kept in memory as notification listeners and
7820 // cause extreme memory pressure.
7821 // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation.
7822 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE
Amith Yamasani5016a782019-06-17 16:20:24 -07007823 | BIND_NOT_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT;
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07007824 }
7825
7826 @Override
John Spurlock7340fc82014-04-24 18:50:12 -04007827 protected Config getConfig() {
7828 Config c = new Config();
7829 c.caption = "notification listener";
7830 c.serviceInterface = NotificationListenerService.SERVICE_INTERFACE;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04007831 c.xmlTag = TAG_ENABLED_NOTIFICATION_LISTENERS;
John Spurlock7340fc82014-04-24 18:50:12 -04007832 c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
7833 c.bindPermission = android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE;
7834 c.settingsAction = Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS;
7835 c.clientLabel = R.string.notification_listener_binding_label;
7836 return c;
7837 }
7838
7839 @Override
7840 protected IInterface asInterface(IBinder binder) {
7841 return INotificationListener.Stub.asInterface(binder);
7842 }
7843
7844 @Override
Chris Wren51017d02015-12-15 15:34:46 -05007845 protected boolean checkType(IInterface service) {
7846 return service instanceof INotificationListener;
7847 }
7848
7849 @Override
John Spurlock3b98b3f2014-05-01 09:08:48 -04007850 public void onServiceAdded(ManagedServiceInfo info) {
7851 final INotificationListener listener = (INotificationListener) info.service;
Chris Wren333a61c2014-05-28 16:40:57 -04007852 final NotificationRankingUpdate update;
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05007853 synchronized (mNotificationLock) {
Chris Wren333a61c2014-05-28 16:40:57 -04007854 update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007855 }
John Spurlock7340fc82014-04-24 18:50:12 -04007856 try {
Chris Wren333a61c2014-05-28 16:40:57 -04007857 listener.onListenerConnected(update);
John Spurlock7340fc82014-04-24 18:50:12 -04007858 } catch (RemoteException e) {
7859 // we tried
7860 }
7861 }
7862
John Spurlock1fa865f2014-07-21 14:56:39 -04007863 @Override
Julia Reynolds88860ce2017-06-01 16:55:49 -04007864 @GuardedBy("mNotificationLock")
John Spurlock1fa865f2014-07-21 14:56:39 -04007865 protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
Bryce Lee7219ada2016-04-08 10:54:23 -07007866 if (removeDisabledHints(removed)) {
John Spurlockd8afe3c2014-08-01 14:04:07 -04007867 updateListenerHintsLocked();
Christoph Studer0d6ef4b2014-12-02 15:00:48 +01007868 updateEffectsSuppressorLocked();
John Spurlock1fa865f2014-07-21 14:56:39 -04007869 }
Christoph Studerb82bc782014-08-20 14:29:43 +02007870 mLightTrimListeners.remove(removed);
7871 }
7872
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -05007873 @Override
7874 protected String getRequiredPermission() {
7875 return null;
7876 }
7877
Julia Reynolds88860ce2017-06-01 16:55:49 -04007878 @GuardedBy("mNotificationLock")
Christoph Studerb82bc782014-08-20 14:29:43 +02007879 public void setOnNotificationPostedTrimLocked(ManagedServiceInfo info, int trim) {
7880 if (trim == TRIM_LIGHT) {
7881 mLightTrimListeners.add(info);
7882 } else {
7883 mLightTrimListeners.remove(info);
7884 }
7885 }
7886
7887 public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
7888 return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
John Spurlock1fa865f2014-07-21 14:56:39 -04007889 }
7890
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05007891 public void onStatusBarIconsBehaviorChanged(boolean hideSilentStatusIcons) {
7892 for (final ManagedServiceInfo info : getServices()) {
7893 mHandler.post(() -> {
7894 final INotificationListener listener = (INotificationListener) info.service;
7895 try {
7896 listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
7897 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00007898 Slog.e(TAG, "unable to notify listener "
Julia Reynolds12ad7ca2019-01-28 09:29:16 -05007899 + "(hideSilentStatusIcons): " + listener, ex);
7900 }
7901 });
7902 }
7903 }
7904
John Spurlock7340fc82014-04-24 18:50:12 -04007905 /**
7906 * asynchronously notify all listeners about a new notification
Christoph Studercef37cf2014-07-25 14:18:17 +02007907 *
7908 * <p>
7909 * Also takes care of removing a notification that has been visible to a listener before,
7910 * but isn't anymore.
John Spurlock7340fc82014-04-24 18:50:12 -04007911 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007912 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007913 public void notifyPostedLocked(NotificationRecord r, NotificationRecord old) {
7914 notifyPostedLocked(r, old, true);
Beverly5a20a5e2018-03-06 15:02:44 -05007915 }
7916
7917 /**
7918 * @param notifyAllListeners notifies all listeners if true, else only notifies listeners
7919 * targetting <= O_MR1
7920 */
7921 @GuardedBy("mNotificationLock")
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007922 private void notifyPostedLocked(NotificationRecord r, NotificationRecord old,
Beverly5a20a5e2018-03-06 15:02:44 -05007923 boolean notifyAllListeners) {
Christoph Studerb82bc782014-08-20 14:29:43 +02007924 // Lazily initialized snapshots of the notification.
Julia Reynoldse0d711f2017-09-01 08:50:47 -04007925 StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007926 StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
Chris Wren47633422016-01-22 09:56:59 -05007927 TrimCache trimCache = new TrimCache(sbn);
Christoph Studerb82bc782014-08-20 14:29:43 +02007928
Julia Reynolds00314d92017-04-14 10:01:24 -04007929 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007930 boolean sbnVisible = isVisibleToListener(sbn, info);
7931 boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false;
7932 // This notification hasn't been and still isn't visible -> ignore.
7933 if (!oldSbnVisible && !sbnVisible) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007934 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007935 }
Beverly5a20a5e2018-03-06 15:02:44 -05007936 // If the notification is hidden, don't notifyPosted listeners targeting < P.
7937 // Instead, those listeners will receive notifyPosted when the notification is
7938 // unhidden.
7939 if (r.isHidden() && info.targetSdkVersion < Build.VERSION_CODES.P) {
7940 continue;
7941 }
7942
7943 // If we shouldn't notify all listeners, this means the hidden state of
7944 // a notification was changed. Don't notifyPosted listeners targeting >= P.
7945 // Instead, those listeners will receive notifyRankingUpdate.
7946 if (!notifyAllListeners && info.targetSdkVersion >= Build.VERSION_CODES.P) {
7947 continue;
7948 }
7949
Chris Wren333a61c2014-05-28 16:40:57 -04007950 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studercef37cf2014-07-25 14:18:17 +02007951
7952 // This notification became invisible -> remove the old one.
7953 if (oldSbnVisible && !sbnVisible) {
7954 final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight();
7955 mHandler.post(new Runnable() {
7956 @Override
7957 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04007958 notifyRemoved(
7959 info, oldSbnLightClone, update, null, REASON_USER_STOPPED);
Christoph Studercef37cf2014-07-25 14:18:17 +02007960 }
7961 });
Christoph Studer05ad4822014-05-16 14:16:03 +02007962 continue;
7963 }
Christoph Studercef37cf2014-07-25 14:18:17 +02007964
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007965 // Grant access before listener is notified
7966 final int targetUserId = (info.userid == UserHandle.USER_ALL)
7967 ? UserHandle.USER_SYSTEM : info.userid;
7968 updateUriPermissions(r, old, info.component.getPackageName(), targetUserId);
Julia Reynoldse0d711f2017-09-01 08:50:47 -04007969
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007970 final StatusBarNotification sbnToPost = trimCache.ForListener(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02007971 mHandler.post(new Runnable() {
7972 @Override
7973 public void run() {
Christoph Studerb82bc782014-08-20 14:29:43 +02007974 notifyPosted(info, sbnToPost, update);
Christoph Studer05ad4822014-05-16 14:16:03 +02007975 }
7976 });
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007977 }
7978 }
Kenny Guy3a7c4a52014-03-03 18:24:03 +00007979
John Spurlock7340fc82014-04-24 18:50:12 -04007980 /**
7981 * asynchronously notify all listeners about a removed notification
7982 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04007983 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05007984 public void notifyRemovedLocked(NotificationRecord r, int reason,
Julia Reynolds503ed942017-10-04 16:04:56 -04007985 NotificationStats notificationStats) {
Beverly5a20a5e2018-03-06 15:02:44 -05007986 final StatusBarNotification sbn = r.sbn;
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06007987
John Spurlock7340fc82014-04-24 18:50:12 -04007988 // make a copy in case changes are made to the underlying Notification object
7989 // NOTE: this copy is lightweight: it doesn't include heavyweight parts of the
7990 // notification
7991 final StatusBarNotification sbnLight = sbn.cloneLight();
Julia Reynolds00314d92017-04-14 10:01:24 -04007992 for (final ManagedServiceInfo info : getServices()) {
Christoph Studercef37cf2014-07-25 14:18:17 +02007993 if (!isVisibleToListener(sbn, info)) {
Christoph Studer05ad4822014-05-16 14:16:03 +02007994 continue;
Chris Wrenf9536642014-04-17 10:01:54 -04007995 }
Beverly5a20a5e2018-03-06 15:02:44 -05007996
7997 // don't notifyRemoved for listeners targeting < P
7998 // if not for reason package suspended
7999 if (r.isHidden() && reason != REASON_PACKAGE_SUSPENDED
8000 && info.targetSdkVersion < Build.VERSION_CODES.P) {
8001 continue;
8002 }
8003
8004 // don't notifyRemoved for listeners targeting >= P
8005 // if the reason is package suspended
8006 if (reason == REASON_PACKAGE_SUSPENDED
8007 && info.targetSdkVersion >= Build.VERSION_CODES.P) {
8008 continue;
8009 }
8010
Julia Reynolds503ed942017-10-04 16:04:56 -04008011 // Only assistants can get stats
8012 final NotificationStats stats = mAssistants.isServiceTokenValidLocked(info.service)
8013 ? notificationStats : null;
Chris Wren333a61c2014-05-28 16:40:57 -04008014 final NotificationRankingUpdate update = makeRankingUpdateLocked(info);
Christoph Studer05ad4822014-05-16 14:16:03 +02008015 mHandler.post(new Runnable() {
8016 @Override
8017 public void run() {
Julia Reynolds503ed942017-10-04 16:04:56 -04008018 notifyRemoved(info, sbnLight, update, stats, reason);
Christoph Studer05ad4822014-05-16 14:16:03 +02008019 }
8020 });
Chris Wrenf9536642014-04-17 10:01:54 -04008021 }
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06008022
8023 // Revoke access after all listeners have been updated
8024 mHandler.post(() -> {
8025 updateUriPermissions(null, r, null, UserHandle.USER_SYSTEM);
8026 });
Chris Wrenf9536642014-04-17 10:01:54 -04008027 }
8028
8029 /**
Beverly5a20a5e2018-03-06 15:02:44 -05008030 * Asynchronously notify all listeners about a reordering of notifications
8031 * unless changedHiddenNotifications is populated.
8032 * If changedHiddenNotifications is populated, there was a change in the hidden state
8033 * of the notifications. In this case, we only send updates to listeners that
8034 * target >= P.
Chris Wrenf9536642014-04-17 10:01:54 -04008035 */
Julia Reynolds88860ce2017-06-01 16:55:49 -04008036 @GuardedBy("mNotificationLock")
Beverly5a20a5e2018-03-06 15:02:44 -05008037 public void notifyRankingUpdateLocked(List<NotificationRecord> changedHiddenNotifications) {
8038 boolean isHiddenRankingUpdate = changedHiddenNotifications != null
8039 && changedHiddenNotifications.size() > 0;
8040
Julia Reynolds00314d92017-04-14 10:01:24 -04008041 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer05ad4822014-05-16 14:16:03 +02008042 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8043 continue;
8044 }
Beverly5a20a5e2018-03-06 15:02:44 -05008045
8046 boolean notifyThisListener = false;
8047 if (isHiddenRankingUpdate && serviceInfo.targetSdkVersion >=
8048 Build.VERSION_CODES.P) {
8049 for (NotificationRecord rec : changedHiddenNotifications) {
8050 if (isVisibleToListener(rec.sbn, serviceInfo)) {
8051 notifyThisListener = true;
8052 break;
8053 }
John Spurlock7340fc82014-04-24 18:50:12 -04008054 }
Beverly5a20a5e2018-03-06 15:02:44 -05008055 }
8056
8057 if (notifyThisListener || !isHiddenRankingUpdate) {
8058 final NotificationRankingUpdate update = makeRankingUpdateLocked(
8059 serviceInfo);
8060
8061 mHandler.post(new Runnable() {
8062 @Override
8063 public void run() {
8064 notifyRankingUpdate(serviceInfo, update);
8065 }
8066 });
8067 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008068 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008069 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008070
Julia Reynolds88860ce2017-06-01 16:55:49 -04008071 @GuardedBy("mNotificationLock")
John Spurlockd8afe3c2014-08-01 14:04:07 -04008072 public void notifyListenerHintsChangedLocked(final int hints) {
Julia Reynolds00314d92017-04-14 10:01:24 -04008073 for (final ManagedServiceInfo serviceInfo : getServices()) {
John Spurlock1fa865f2014-07-21 14:56:39 -04008074 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8075 continue;
8076 }
8077 mHandler.post(new Runnable() {
8078 @Override
8079 public void run() {
John Spurlockd8afe3c2014-08-01 14:04:07 -04008080 notifyListenerHintsChanged(serviceInfo, hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04008081 }
8082 });
8083 }
8084 }
8085
Beverly5a20a5e2018-03-06 15:02:44 -05008086 /**
8087 * asynchronously notify relevant listeners their notification is hidden
8088 * NotificationListenerServices that target P+:
8089 * NotificationListenerService#notifyRankingUpdateLocked()
8090 * NotificationListenerServices that target <= P:
8091 * NotificationListenerService#notifyRemovedLocked() with REASON_PACKAGE_SUSPENDED.
8092 */
8093 @GuardedBy("mNotificationLock")
8094 public void notifyHiddenLocked(List<NotificationRecord> changedNotifications) {
8095 if (changedNotifications == null || changedNotifications.size() == 0) {
8096 return;
8097 }
8098
8099 notifyRankingUpdateLocked(changedNotifications);
8100
8101 // for listeners that target < P, notifyRemoveLocked
8102 int numChangedNotifications = changedNotifications.size();
8103 for (int i = 0; i < numChangedNotifications; i++) {
8104 NotificationRecord rec = changedNotifications.get(i);
8105 mListeners.notifyRemovedLocked(rec, REASON_PACKAGE_SUSPENDED, rec.getStats());
8106 }
8107 }
8108
8109 /**
8110 * asynchronously notify relevant listeners their notification is unhidden
8111 * NotificationListenerServices that target P+:
8112 * NotificationListenerService#notifyRankingUpdateLocked()
8113 * NotificationListenerServices that target <= P:
8114 * NotificationListeners#notifyPostedLocked()
8115 */
8116 @GuardedBy("mNotificationLock")
8117 public void notifyUnhiddenLocked(List<NotificationRecord> changedNotifications) {
8118 if (changedNotifications == null || changedNotifications.size() == 0) {
8119 return;
8120 }
8121
8122 notifyRankingUpdateLocked(changedNotifications);
8123
8124 // for listeners that target < P, notifyPostedLocked
8125 int numChangedNotifications = changedNotifications.size();
8126 for (int i = 0; i < numChangedNotifications; i++) {
8127 NotificationRecord rec = changedNotifications.get(i);
Jeff Sharkey6a97cc32018-04-17 12:16:20 -06008128 mListeners.notifyPostedLocked(rec, rec, false);
Beverly5a20a5e2018-03-06 15:02:44 -05008129 }
8130 }
8131
Christoph Studer85a384b2014-08-27 20:16:15 +02008132 public void notifyInterruptionFilterChanged(final int interruptionFilter) {
Julia Reynolds00314d92017-04-14 10:01:24 -04008133 for (final ManagedServiceInfo serviceInfo : getServices()) {
Christoph Studer85a384b2014-08-27 20:16:15 +02008134 if (!serviceInfo.isEnabledForCurrentProfiles()) {
8135 continue;
8136 }
8137 mHandler.post(new Runnable() {
8138 @Override
8139 public void run() {
8140 notifyInterruptionFilterChanged(serviceInfo, interruptionFilter);
8141 }
8142 });
8143 }
8144 }
8145
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008146 protected void notifyNotificationChannelChanged(final String pkg, final UserHandle user,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008147 final NotificationChannel channel, final int modificationType) {
8148 if (channel == null) {
8149 return;
8150 }
8151 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04008152 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008153 continue;
8154 }
Julia Reynolds018aa622017-04-20 11:31:30 -04008155
Eugene Suslaa25d17f2017-08-24 11:28:08 -07008156 BackgroundThread.getHandler().post(() -> {
8157 if (hasCompanionDevice(serviceInfo)) {
8158 notifyNotificationChannelChanged(
8159 serviceInfo, pkg, user, channel, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04008160 }
8161 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008162 }
8163 }
8164
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008165 protected void notifyNotificationChannelGroupChanged(
8166 final String pkg, final UserHandle user, final NotificationChannelGroup group,
8167 final int modificationType) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008168 if (group == null) {
8169 return;
8170 }
8171 for (final ManagedServiceInfo serviceInfo : getServices()) {
Julia Reynoldsda781472017-04-12 09:41:16 -04008172 if (!serviceInfo.enabledAndUserMatches(UserHandle.getCallingUserId())) {
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008173 continue;
8174 }
Julia Reynolds018aa622017-04-20 11:31:30 -04008175
Eugene Suslaa25d17f2017-08-24 11:28:08 -07008176 BackgroundThread.getHandler().post(() -> {
8177 if (hasCompanionDevice(serviceInfo)) {
8178 notifyNotificationChannelGroupChanged(
8179 serviceInfo, pkg, user, group, modificationType);
Julia Reynoldsda781472017-04-12 09:41:16 -04008180 }
8181 });
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008182 }
8183 }
8184
Christoph Studercef37cf2014-07-25 14:18:17 +02008185 private void notifyPosted(final ManagedServiceInfo info,
Christoph Studer05ad4822014-05-16 14:16:03 +02008186 final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04008187 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008188 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04008189 try {
Griff Hazen84a00ea2014-09-02 17:10:47 -07008190 listener.onNotificationPosted(sbnHolder, rankingUpdate);
John Spurlock7340fc82014-04-24 18:50:12 -04008191 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008192 Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
John Spurlock7340fc82014-04-24 18:50:12 -04008193 }
8194 }
8195
Christoph Studercef37cf2014-07-25 14:18:17 +02008196 private void notifyRemoved(ManagedServiceInfo info, StatusBarNotification sbn,
Julia Reynolds503ed942017-10-04 16:04:56 -04008197 NotificationRankingUpdate rankingUpdate, NotificationStats stats, int reason) {
John Spurlock7340fc82014-04-24 18:50:12 -04008198 if (!info.enabledAndUserMatches(sbn.getUserId())) {
8199 return;
8200 }
Christoph Studer05ad4822014-05-16 14:16:03 +02008201 final INotificationListener listener = (INotificationListener) info.service;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008202 StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
John Spurlock7340fc82014-04-24 18:50:12 -04008203 try {
Julia Reynolds503ed942017-10-04 16:04:56 -04008204 listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
John Spurlock7340fc82014-04-24 18:50:12 -04008205 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008206 Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
John Spurlockb408e8e2014-04-23 21:12:45 -04008207 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008208 }
Chris Wrenf9536642014-04-17 10:01:54 -04008209
Christoph Studer05ad4822014-05-16 14:16:03 +02008210 private void notifyRankingUpdate(ManagedServiceInfo info,
8211 NotificationRankingUpdate rankingUpdate) {
8212 final INotificationListener listener = (INotificationListener) info.service;
Chris Wrenf9536642014-04-17 10:01:54 -04008213 try {
Christoph Studer05ad4822014-05-16 14:16:03 +02008214 listener.onNotificationRankingUpdate(rankingUpdate);
Chris Wrenf9536642014-04-17 10:01:54 -04008215 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008216 Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
Chris Wrenf9536642014-04-17 10:01:54 -04008217 }
8218 }
John Spurlock1fa865f2014-07-21 14:56:39 -04008219
John Spurlockd8afe3c2014-08-01 14:04:07 -04008220 private void notifyListenerHintsChanged(ManagedServiceInfo info, int hints) {
John Spurlock1fa865f2014-07-21 14:56:39 -04008221 final INotificationListener listener = (INotificationListener) info.service;
8222 try {
John Spurlockd8afe3c2014-08-01 14:04:07 -04008223 listener.onListenerHintsChanged(hints);
John Spurlock1fa865f2014-07-21 14:56:39 -04008224 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008225 Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
John Spurlock1fa865f2014-07-21 14:56:39 -04008226 }
8227 }
Justin Koh38156c52014-06-04 13:57:49 -07008228
Christoph Studer85a384b2014-08-27 20:16:15 +02008229 private void notifyInterruptionFilterChanged(ManagedServiceInfo info,
8230 int interruptionFilter) {
8231 final INotificationListener listener = (INotificationListener) info.service;
8232 try {
8233 listener.onInterruptionFilterChanged(interruptionFilter);
8234 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008235 Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
Christoph Studer85a384b2014-08-27 20:16:15 +02008236 }
8237 }
8238
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008239 void notifyNotificationChannelChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008240 final String pkg, final UserHandle user, final NotificationChannel channel,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008241 final int modificationType) {
8242 final INotificationListener listener = (INotificationListener) info.service;
8243 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008244 listener.onNotificationChannelModification(pkg, user, channel, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008245 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008246 Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008247 }
8248 }
8249
8250 private void notifyNotificationChannelGroupChanged(ManagedServiceInfo info,
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008251 final String pkg, final UserHandle user, final NotificationChannelGroup group,
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008252 final int modificationType) {
8253 final INotificationListener listener = (INotificationListener) info.service;
8254 try {
Julia Reynoldsf27d6b22017-04-13 15:48:16 -04008255 listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008256 } catch (RemoteException ex) {
Tony Mak180a9c42019-03-08 13:33:08 +00008257 Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
Julia Reynolds73ed76b2017-04-04 17:04:38 -04008258 }
8259 }
8260
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05008261 public boolean isListenerPackage(String packageName) {
Justin Koh38156c52014-06-04 13:57:49 -07008262 if (packageName == null) {
8263 return false;
8264 }
8265 // TODO: clean up locking object later
Geoffrey Pitsch331a64d2017-01-17 14:00:47 -05008266 synchronized (mNotificationLock) {
Julia Reynolds00314d92017-04-14 10:01:24 -04008267 for (final ManagedServiceInfo serviceInfo : getServices()) {
Justin Koh38156c52014-06-04 13:57:49 -07008268 if (packageName.equals(serviceInfo.component.getPackageName())) {
8269 return true;
8270 }
8271 }
8272 }
8273 return false;
8274 }
Kenny Guya263e4e2014-03-03 18:24:03 +00008275 }
John Spurlock25e2d242014-06-27 13:58:23 -04008276
Julia Reynolds0c245002019-03-27 16:10:11 -04008277 class RoleObserver implements OnRoleHoldersChangedListener {
8278 // Role name : user id : list of approved packages
8279 private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
8280
8281 private final RoleManager mRm;
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008282 private final IPackageManager mPm;
Julia Reynolds0c245002019-03-27 16:10:11 -04008283 private final Executor mExecutor;
8284
8285 RoleObserver(@NonNull RoleManager roleManager,
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008286 @NonNull IPackageManager pkgMgr,
Julia Reynolds0c245002019-03-27 16:10:11 -04008287 @NonNull @CallbackExecutor Executor executor) {
8288 mRm = roleManager;
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008289 mPm = pkgMgr;
Julia Reynolds0c245002019-03-27 16:10:11 -04008290 mExecutor = executor;
8291 }
8292
8293 public void init() {
8294 List<UserInfo> users = mUm.getUsers();
8295 mNonBlockableDefaultApps = new ArrayMap<>();
8296 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
8297 final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
8298 mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
8299 for (int j = 0; j < users.size(); j++) {
8300 Integer userId = users.get(j).getUserHandle().getIdentifier();
8301 ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
8302 NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008303 ArraySet<Pair<String, Integer>> approvedAppUids = new ArraySet<>();
8304 for (String pkg : approvedForUserId) {
8305 approvedAppUids.add(new Pair(pkg, getUidForPackage(pkg, userId)));
8306 }
Julia Reynolds0c245002019-03-27 16:10:11 -04008307 userToApprovedList.put(userId, approvedForUserId);
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008308 mPreferencesHelper.updateDefaultApps(userId, null, approvedAppUids);
Julia Reynolds0c245002019-03-27 16:10:11 -04008309 }
8310 }
8311
8312 mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
8313 }
8314
8315 @VisibleForTesting
8316 public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) {
8317 return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);
8318 }
8319
8320 /**
8321 * Convert the assistant-role holder into settings. The rest of the system uses the
8322 * settings.
8323 *
8324 * @param roleName the name of the role whose holders are changed
8325 * @param user the user for this role holder change
8326 */
8327 @Override
8328 public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
8329 // we only care about a couple of the roles they'll tell us about
8330 boolean relevantChange = false;
8331 for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
8332 if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) {
8333 relevantChange = true;
8334 break;
8335 }
8336 }
8337
8338 if (!relevantChange) {
8339 return;
8340 }
8341
8342 ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user));
8343
8344 // find the diff
8345 ArrayMap<Integer, ArraySet<String>> prevApprovedForRole =
8346 mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>());
8347 ArraySet<String> previouslyApproved =
8348 prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
8349
8350 ArraySet<String> toRemove = new ArraySet<>();
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008351 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>();
Julia Reynolds0c245002019-03-27 16:10:11 -04008352
8353 for (String previous : previouslyApproved) {
8354 if (!roleHolders.contains(previous)) {
8355 toRemove.add(previous);
8356 }
8357 }
8358 for (String nowApproved : roleHolders) {
8359 if (!previouslyApproved.contains(nowApproved)) {
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008360 toAdd.add(new Pair(nowApproved,
8361 getUidForPackage(nowApproved, user.getIdentifier())));
Julia Reynolds0c245002019-03-27 16:10:11 -04008362 }
8363 }
8364
8365 // store newly approved apps
8366 prevApprovedForRole.put(user.getIdentifier(), roleHolders);
8367 mNonBlockableDefaultApps.put(roleName, prevApprovedForRole);
8368
8369 // update what apps can be blocked
8370 mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd);
8371
8372 // RoleManager is the source of truth for this data so we don't need to trigger a
8373 // write of the notification policy xml for this change
8374 }
Julia Reynoldse7ca31b2019-04-25 15:41:47 -04008375
8376 private int getUidForPackage(String pkg, int userId) {
8377 try {
8378 return mPm.getPackageUid(pkg, MATCH_ALL, userId);
8379 } catch (RemoteException e) {
8380 Slog.e(TAG, "role manager has bad default " + pkg + " " + userId);
8381 }
8382 return -1;
8383 }
Julia Reynolds0c245002019-03-27 16:10:11 -04008384 }
8385
John Spurlock25e2d242014-06-27 13:58:23 -04008386 public static final class DumpFilter {
Dan Sandlera1770312015-07-10 13:59:29 -04008387 public boolean filtered = false;
John Spurlock25e2d242014-06-27 13:58:23 -04008388 public String pkgFilter;
John Spurlock50806fc2014-07-15 10:22:02 -04008389 public boolean zen;
Chris Wrene4b38802015-07-07 15:54:19 -04008390 public long since;
8391 public boolean stats;
Dan Sandlera1770312015-07-10 13:59:29 -04008392 public boolean redact = true;
Julia Reynoldsc9842c12017-02-07 12:46:41 -05008393 public boolean proto = false;
Vishnu Naire3e4d252018-03-01 11:26:57 -08008394 public boolean criticalPriority = false;
8395 public boolean normalPriority = false;
John Spurlock25e2d242014-06-27 13:58:23 -04008396
Kweku Adams887f09c2017-11-13 17:12:20 -08008397 @NonNull
John Spurlock25e2d242014-06-27 13:58:23 -04008398 public static DumpFilter parseFromArguments(String[] args) {
Dan Sandlera1770312015-07-10 13:59:29 -04008399 final DumpFilter filter = new DumpFilter();
8400 for (int ai = 0; ai < args.length; ai++) {
8401 final String a = args[ai];
Kweku Adams62b42242017-09-25 12:54:02 -07008402 if ("--proto".equals(a)) {
Julia Reynoldsc9842c12017-02-07 12:46:41 -05008403 filter.proto = true;
Kweku Adams62b42242017-09-25 12:54:02 -07008404 } else if ("--noredact".equals(a) || "--reveal".equals(a)) {
Dan Sandlera1770312015-07-10 13:59:29 -04008405 filter.redact = false;
8406 } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) {
8407 if (ai < args.length-1) {
8408 ai++;
8409 filter.pkgFilter = args[ai].trim().toLowerCase();
8410 if (filter.pkgFilter.isEmpty()) {
8411 filter.pkgFilter = null;
8412 } else {
8413 filter.filtered = true;
8414 }
8415 }
8416 } else if ("--zen".equals(a) || "zen".equals(a)) {
8417 filter.filtered = true;
8418 filter.zen = true;
8419 } else if ("--stats".equals(a)) {
8420 filter.stats = true;
8421 if (ai < args.length-1) {
8422 ai++;
Tobias Thierer28532d02016-04-21 14:52:10 +01008423 filter.since = Long.parseLong(args[ai]);
Dan Sandlera1770312015-07-10 13:59:29 -04008424 } else {
8425 filter.since = 0;
8426 }
Vishnu Naire3e4d252018-03-01 11:26:57 -08008427 } else if (PRIORITY_ARG.equals(a)) {
8428 // Bugreport will call the service twice with priority arguments, first to dump
8429 // critical sections and then non critical ones. Set approriate filters
8430 // to generate the desired data.
8431 if (ai < args.length - 1) {
8432 ai++;
8433 switch (args[ai]) {
8434 case PRIORITY_ARG_CRITICAL:
8435 filter.criticalPriority = true;
8436 break;
8437 case PRIORITY_ARG_NORMAL:
8438 filter.normalPriority = true;
8439 break;
8440 }
8441 }
Dan Sandlera1770312015-07-10 13:59:29 -04008442 }
John Spurlock25e2d242014-06-27 13:58:23 -04008443 }
Dan Sandlera1770312015-07-10 13:59:29 -04008444 return filter;
John Spurlock25e2d242014-06-27 13:58:23 -04008445 }
8446
8447 public boolean matches(StatusBarNotification sbn) {
Dan Sandlera1770312015-07-10 13:59:29 -04008448 if (!filtered) return true;
8449 return zen ? true : sbn != null
John Spurlock50806fc2014-07-15 10:22:02 -04008450 && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
John Spurlock25e2d242014-06-27 13:58:23 -04008451 }
8452
8453 public boolean matches(ComponentName component) {
Dan Sandlera1770312015-07-10 13:59:29 -04008454 if (!filtered) return true;
8455 return zen ? true : component != null && matches(component.getPackageName());
John Spurlock25e2d242014-06-27 13:58:23 -04008456 }
8457
8458 public boolean matches(String pkg) {
Dan Sandlera1770312015-07-10 13:59:29 -04008459 if (!filtered) return true;
8460 return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
John Spurlock50806fc2014-07-15 10:22:02 -04008461 }
8462
8463 @Override
8464 public String toString() {
Chris Wrene4b38802015-07-07 15:54:19 -04008465 return stats ? "stats" : zen ? "zen" : ('\'' + pkgFilter + '\'');
John Spurlock25e2d242014-06-27 13:58:23 -04008466 }
8467 }
Griff Hazen84a00ea2014-09-02 17:10:47 -07008468
Beverly5a20a5e2018-03-06 15:02:44 -05008469 @VisibleForTesting
Tony Mak9a3c1f12019-03-04 16:04:42 +00008470 void resetAssistantUserSet(int userId) {
8471 mAssistants.setUserSet(userId, false);
8472 handleSavePolicyFile();
8473 }
8474
8475 @VisibleForTesting
8476 @Nullable
8477 ComponentName getApprovedAssistant(int userId) {
8478 List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
8479 return CollectionUtils.firstOrNull(allowedComponents);
8480 }
8481
8482 @VisibleForTesting
Beverly5a20a5e2018-03-06 15:02:44 -05008483 protected void simulatePackageSuspendBroadcast(boolean suspend, String pkg) {
8484 // only use for testing: mimic receive broadcast that package is (un)suspended
8485 // but does not actually (un)suspend the package
8486 final Bundle extras = new Bundle();
8487 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST,
8488 new String[]{pkg});
8489
8490 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED
Beverly3c707b42018-09-14 09:49:07 -04008491 : Intent.ACTION_PACKAGES_UNSUSPENDED;
Beverly5a20a5e2018-03-06 15:02:44 -05008492 final Intent intent = new Intent(action);
8493 intent.putExtras(extras);
8494
8495 mPackageIntentReceiver.onReceive(getContext(), intent);
8496 }
8497
Julia Reynolds0e5a3432019-01-17 09:40:46 -05008498 @VisibleForTesting
8499 protected void simulatePackageDistractionBroadcast(int flag, String[] pkgs) {
8500 // only use for testing: mimic receive broadcast that package is (un)distracting
8501 // but does not actually register that info with packagemanager
8502 final Bundle extras = new Bundle();
8503 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs);
8504 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag);
8505
8506 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED);
8507 intent.putExtras(extras);
8508
8509 mPackageIntentReceiver.onReceive(getContext(), intent);
8510 }
8511
Griff Hazen84a00ea2014-09-02 17:10:47 -07008512 /**
8513 * Wrapper for a StatusBarNotification object that allows transfer across a oneway
8514 * binder without sending large amounts of data over a oneway transaction.
8515 */
8516 private static final class StatusBarNotificationHolder
8517 extends IStatusBarNotificationHolder.Stub {
Griff Hazene9aac5f2014-09-05 20:04:09 -07008518 private StatusBarNotification mValue;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008519
8520 public StatusBarNotificationHolder(StatusBarNotification value) {
8521 mValue = value;
8522 }
8523
Griff Hazene9aac5f2014-09-05 20:04:09 -07008524 /** Get the held value and clear it. This function should only be called once per holder */
Griff Hazen84a00ea2014-09-02 17:10:47 -07008525 @Override
8526 public StatusBarNotification get() {
Griff Hazene9aac5f2014-09-05 20:04:09 -07008527 StatusBarNotification value = mValue;
8528 mValue = null;
8529 return value;
Griff Hazen84a00ea2014-09-02 17:10:47 -07008530 }
8531 }
John Spurlock7c74f782015-06-04 13:01:42 -04008532
Zimuzob3b9c262018-10-31 11:54:20 +00008533 private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
8534 out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
8535 out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
8536 Boolean.toString(mLockScreenAllowSecureNotifications));
8537 out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
8538 }
8539
8540 private static boolean safeBoolean(String val, boolean defValue) {
8541 if (TextUtils.isEmpty(val)) return defValue;
8542 return Boolean.parseBoolean(val);
8543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008544}